河南app軟件開發(fā)價位怎么優(yōu)化一個網(wǎng)站關(guān)鍵詞
本文簡介
點贊 + 關(guān)注 + 收藏 = 學(xué)會了
本文介紹一個能讓前端優(yōu)雅下載大文件的工具:StreamSaver.js
- ?? StreamSaver.js GitHub地址
- ?? 官方案例
StreamSaver.js
可用于實現(xiàn)在Web瀏覽器中直接將大文件流式傳輸?shù)接脩粼O(shè)備的功能。
傳統(tǒng)的下載方式可能導(dǎo)致大文件的加載時間較長或造成內(nèi)存占用過大的問題,使用 <a>
標(biāo)簽打開新頁面下載文件,遇到 .txt
或者 .mp4
之類的文件可能就直接在頁面展示了,不會觸發(fā)下載功能。而 StreamSaver.js
則通過流式下載的方式解決了這些問題。
StreamSaver.js
將大文件拆分成小塊,并在下載過程中逐塊傳輸?shù)接脖P,從而降低內(nèi)存占用和提高下載速度。
環(huán)境準(zhǔn)備
要學(xué)習(xí) StreamSaver.js
首先要準(zhǔn)備一份或者多份可下載的文件。
你可以使用網(wǎng)絡(luò)上的文件資源,但這需要你自己去找。
你也可以在自己的電腦運行個服務(wù),把文件資源丟進去即可。
如果你用腳手架創(chuàng)建項目,比如vue或者react之類的項目,也可以把文件放在靜態(tài)資源目錄里。
比如用 vite
創(chuàng)建一個 Vue
項目,然后在 public
目錄下創(chuàng)建一個 test.txt
文件。項目運行起來,在瀏覽器訪問 http://localhost:端口號/public/test.txt
就能查看到這個文件內(nèi)容。
安裝 StreamSaver.js
可以使用 CDN
或者 npm
安裝 StreamSaver.js
。
本文使用 CDN
的方式講解。
CDN
打開 StreamSaver.js的倉庫。
把 StreamSaver.js
文件下載到你項目里引入即可。
<script src="../StreamSaver.js"></script>
npm
??StreamSaver npm地址
使用以下命令下載 StreamSaver
到項目里
npm i streamsaver
然后在要使用的地方引入即可。
import streamSaver from "streamsaver"
起步
起步階段,我們先試試如何下載一個 .txt
文件。
如果我們要下載一些瀏覽器讀不懂的文件,我們可以使用 <a>
標(biāo)簽在新窗口打開鏈接,也可以使用 windows.open('url')
的方式打開新窗口進行下載。
但如果這個文件瀏覽器是讀得懂的,比如 .txt
文件,那瀏覽器就不會執(zhí)行下載,而是會直接在頁面中把文件內(nèi)容展示出來。
此時就可以使用 StreamSaver.js
來解決這個問題。
使用 StreamSaver.js
下載文件的大概流程是這樣的(為了方便理解,我用一些不專業(yè)的術(shù)語進行描述):
- 創(chuàng)建一個文件,該文件支持寫入操作。
streamSaver.createWriteStream('文件名.后綴')
。 - 使用
fetch
方法訪問文件的url,將內(nèi)容一點點的放到StreamSaver
創(chuàng)建的文件里。 - 監(jiān)聽文件內(nèi)容是否讀取完整,讀取完就執(zhí)行“保存并關(guān)閉文件”的操作。
根據(jù)上面的指引編寫代碼:
<!-- 下載按鈕 -->
<button id="download">下載</button><!-- 引入StreamSaver.js -->
<script src="../StreamSaver.js"></script>
<script>// 監(jiān)聽按鈕點擊事件,點擊就下載文件download.onclick = () => {// 【步驟1】創(chuàng)建一個文件,該文件支持寫入操作const fileStream = streamSaver.createWriteStream('test.txt') // 這里傳入的是下載后的文件名,這個名字可以自定義// 【步驟2】使用 fetch 方法訪問文件的url,將內(nèi)容一點點的放到 StreamSaver 創(chuàng)建的文件里fetch('http://localhost:9988/public/test.txt').then(res => {const readableStream = res.bodyif (window.WritableStream && readableStream.pipeTo) {return readableStream.pipeTo(fileStream).then(() => console.log('完成寫入'))}// 【步驟3】監(jiān)聽文件內(nèi)容是否讀取完整,讀取完就執(zhí)行“保存并關(guān)閉文件”的操作。window.writer = fileStream.getWriter()const reader = res.body.getReader()const pump = () => reader.read().then(res => res.done? writer.close(): writer.write(res.value).then(pump))pump()})}
</script>
大概就是這樣子了。
🔔提示
如果遇到提示跨域的問題,可以配置 mitm
指向 mitm.html
。
mitm.html
在 StreamSaver.js倉庫
里可以獲取到。
可以把 mitm.html
放到你服務(wù)器再配置。
streamSaver.mitm = 'https://你的服務(wù)器地址/mitm.html'
打包下載 zip
如果想將多個文件打包成zip下載到本地,可以將 StreamSaver.js
和 zip-stream.js
結(jié)合在一起使用。
zip-stream.js
在 StreamSaver.js
的倉庫里有。
zip-stream.js
在 /examples
目錄里。
使用 npm
安裝 streamsaver
也能在 /examples
目錄下找到 zip-stream.js
,直接引入即可。
import 'node_modules/streamsaver/examples/zip-stream.js'
如果使用 CDN
的方式就直接用 <script src='zip-stream.js'></script>
引入即可。
打包zip下載的步驟:
- 創(chuàng)建下載后的文件名和文件格式。
- 使用
zip-stream
創(chuàng)建一個ZIP
實例,用來不斷接收要下載的文件。 - 所有文件下載完成就執(zhí)行
close()
方法將所有文件真正打包成一個zip
。
<button id="download">下載</button><script src="../StreamSaver.js"></script>
<script src="zip-stream.js"></script>
<script>// 要下載的文件地址列表let urls = [{fileName: 'test.txt',url: 'http://localhost:9988/public/test.txt',},{fileName: 'test.csv',url: 'http://localhost:9988/public/test.csv',}]download.onclick = () => {// 【步驟1】const fileStream = streamSaver.createWriteStream('test.zip')// 【步驟2】const readableZipStream = new ZIP({async pull(ctrl) {for (let i = 0; i < urls.length; i++) {const res = await fetch(urls[i].url)const stream = () => res.bodyconst name = urls[i].fileNamectrl.enqueue({ name, stream }) // 不斷接收要下載的文件}// 【步驟3】ctrl.close()}})if (window.WritableStream && readableZipStream.pipeTo) {return readableZipStream.pipeTo(fileStream).then(() => console.log('下載完了'))}}</script>
點擊下載按鈕后的效果:
這個例子準(zhǔn)備了 .csv
和 .txt
文件。下載時會合并成 .zip
,解壓后能看到里面的所有文件都是正常能打開的 。
合成文件再下載
在這個例子中,我要將2個 .csv
文件合并成1個再下載。
我準(zhǔn)備了兩個 .csv
文件(test1.csv 和 test2.csv),它們的內(nèi)容分別長這個樣子。
我要將它們合并成這樣子:
在合并文件之前我們首先要清楚這個文件的內(nèi)容是如何組成的。
在 Excel 中打開 .csv
的每個單元格的內(nèi)容轉(zhuǎn)換成文本形式的話是用逗號分隔。
如果要合并多個 .csv
文件,只需監(jiān)聽到每個 .csv
下載完成,然后再拼接一個 \n
換行,再下載下一個 .csv
文件即可。
整理一下就是以下幾個步驟:
- 拿到一組下載地址,把它們轉(zhuǎn)存到一個迭代器里。
- 遞歸執(zhí)行迭代器,如果迭代器里還有內(nèi)容,就使用
fetch
請求數(shù)據(jù)。 - 如果迭代器沒內(nèi)容了,使用
writer.close()
關(guān)閉文件寫入。
該功能寫成真正的代碼如下所示:
<button id="download" οnclick="down()">下載</button><script src="../StreamSaver.js"></script>
<script>// 編碼轉(zhuǎn)換方法let encode = TextEncoder.prototype.encode.bind(new TextEncoder)// 準(zhǔn)備好要下載的鏈接const urls = ['http://localhost:9988/public/test1.csv','http://localhost:9988/public/test2.csv']// 迭代器數(shù)據(jù)let urlsIter = null// 寫入方法放到全局中保存let writer = null// 下載按鈕點擊事件function down() {// 創(chuàng)建一個下載管道,并將下載后的文件命名為 newTest.csvconst fileStream = streamSaver.createWriteStream('newTest.csv')// 創(chuàng)建寫入方法writer = fileStream.getWriter()// 將要下載的鏈接轉(zhuǎn)換成迭代器urlsIter = urls[Symbol.iterator]()// 開始執(zhí)行循環(huán)下載forDown()}// 循環(huán)下載的方法async function forDown() {// 獲取迭代器最新一條數(shù)據(jù)let urlIter = urlsIter.next()// 如果迭代器沒數(shù)據(jù),執(zhí)行寫入完成操作,并停止遞歸if (urlIter.done) {writer.close()return}// 迭代器有內(nèi)容時執(zhí)行請求操作await fetch(urlIter.value).then(res => {// 通過請求文件url獲取到的數(shù)據(jù)const readableStream = res.bodyif (window.WritableStream && readableStream.pipeTo) {const reader = readableStream.getReader()// 講獲取到的每一包寫入文件里const pump = () => {return reader.read().then(readRes => {if (readRes.done) { // 當(dāng)前文件讀取完成后執(zhí)行// 文件讀取完成后換行writer.write(encode('\n'))// 執(zhí)行請求下一個文件forDown()} else { // 文件讀取過程執(zhí)行// 一包包寫入writer.write(readRes.value).then(pump)}})}pump()}})}
</script>
這個案例稍微復(fù)雜一丟丟,建議跟著手敲一遍。
推薦閱讀
除了本文所講內(nèi)容外,StreamSaver.js
的倉庫還有好幾個實用的例子,有需要的工友可以去看看。
👍《前端中文漢字轉(zhuǎn)拼音》
👍《提升日期處理效率:day.js 實戰(zhàn)經(jīng)驗分享》
👍《眨個眼就學(xué)會了Pixi.js》
👍《OpenLayers.js 入門教程:打造互動地圖的入門指南》
👍《物理世界的互動之旅:Matter.js入門指南》
👍《p5.js 光速入門》
點贊 + 關(guān)注 + 收藏 = 學(xué)會了 代碼倉庫