博客地址:https://ainyi.com/88
對於 Blob,前端開發中可能比較少遇到;數據庫中可使用 Blob 概念,例如 Mysql 存儲二進制數據的類型就是 Blob,也就是說圖片可存儲於數據庫中,以二進制格式存儲
Blob 對象表示一個不可變、原始數據的類文件對象。File 接口基於Blob,繼承了 blob 的功能並將其擴展使其支持用戶系統上的文件
Blob 是二進制數據對象,是類文件對象的二進制數據
我在之前有篇博客說到 Blob:利用 Blob 處理 Node 層返回的二進制文件流字符串並下載文件
這里我利用 Blob 實現文件拆分再合並下載的方法,算是第一次使用
我們最常見的應該是 Blob URL 技術,文件上傳的預覽、視頻播放的 src,均是采用這種技術實現
Blob URL 就是以 blob: 開頭的一段地址,指向的是一個二進制數據
使用 URL.createObjectURL(blob) 方法生成,參數為 Blob 對象
這個 Blob URL 是可以直接訪問的;需要注意的是這個 URL 的生效時間,等同於網頁的存在時間,一旦網頁刷新或關閉,這個 Blob URL 就失效
構造函數
Blob(blobParts[, options])
返回一個新創建的 Blob 對象,其內容由參數中給定的數組串聯組成
參數說明:
blobParts:數組類型,數組中的每一項連接起來構成 Blob 對象的數據,數組中的每項元素可以是ArrayBuffer, ArrayBufferView, Blob, DOMString
options:可選參數;字典格式類型,可以指定如下兩個屬性:
- type:放入到 blob 中的數組內容的 MIME 類型 MIME 參考手冊
- endings:用於指定包含行結束符\n的字符串如何被寫入;可設置值:native、transparent;native:表示行結束符會被更改為適合宿主操作系統文件系統的換行符; transparent:表示會保持blob中保存的結束符不變;默認值為 transparent;
使用場景
介紹三種使用場景
- 二進制流文件下載
- 圖片預覽
- 視頻加載
二進制流文件下載
// 獲取文件二進制流 content
const content = await downloadContract(params)
// 再利用 Buffer 轉為對象
const buf = Buffer.from(content, 'binary')
// 生成 Blob 對象,type 類型設置為 pdf 的 MIME 類型
const blob = new Blob([buf], {type: 'application/pdf'});
// 獲取 Blob URL,可賦值到 a 標簽 href 屬性進行下載
const url = URL.createObjectURL(blob)
通過 Blob 生成文件、利用 Blob URL 獲取下載鏈接,這樣就實現后端返回二進制格式的文件進行合並再下載
圖片預覽
較為簡單,獲取文件對象后,再通過 createObjectURL 方法得到 Blob URL
最后直接賦值到 img 標簽的 src 屬性即可
<input id="upload" type="file" />
<img id="preview" src="" alt="預覽"/>
const upload = document.querySelector('#upload')
const preview = document.querySelector('#preview')
upload.onchange = function() {
const file = upload.files[0] // File 對象
const src = URL.createObjectURL(file)
preview.src = src
}
視頻加載
視頻地址,不同於上面的 input,可以直接拿到 File 對象
只有一個視頻地址怎么能將這個 URL 變成我們想要的 Blob URL 形式呢
從 URL.createObjectURL(blob) 方法來看,首先要拿到存儲這個視頻原始數據的 Blob 對象
平時我們請求接口可以使用 axios / ajax / xhr 或 fetch,請求一個服務端地址可以返回我們相應的數據,那如果我們去請求一個圖片或視頻地址會返回什么?應當是返回圖片和視頻的數據,這種情況只要設置正確responseType才能拿到我們想要的格式數據
// responseType 參數如下:
// text 字符串;blob Blob對象;arraybuffer ArrayBuffer 對象
function ajax(url, cb) {
const xhr = new XMLHttpRequest()
xhr.open('get', url)
xhr.responseType = 'blob'
xhr.onload = function() {
cb(xhr.response)
}
xhr.send()
}
上面請求返回一個 Blob 對象,接下來只要然后通過 createObjectURL 生成 Blob URL 賦值給視頻的 src 屬性就可以了
ajax('video.mp4', function(res){
const src = URL.createObjectURL(res)
video.src = src
})
大文件分片上傳
最近看到一篇文章:大規格文件的上傳優化
里面講的是利用 Blob 實現文件分片上傳,對於大文件上傳有很好的效果
其核心思想是文件分片,使用 File.slice() 方法進行文件分片;File 對象是繼承 Blob 對象的,因此 File 對象也有 slice 方法
Blob.slice([start[, end[, contentType]]])
start 可選
這個參數代表 Blob 里的下標,表示第一個會被會被拷貝進新的 Blob 的字節的起始位置。如果你傳入的是一個負數,那么這個偏移量將會從數據的末尾從后到前開始計算
舉例來說: -10 將會是 Blob 的倒數第十個字節。它的默認值是0, 如果你傳入的start的長度大於源 Blob 的長度,那么返回的將會是一個長度為0並且不包含任何數據的一個 Blob 對象
end 可選
這個參數代表的是 Blob 的一個下標,這個下標-1的對應的字節將會是被拷貝進新的Blob 的最后一個字節。如果你傳入了一個負數,那么這個偏移量將會從數據的末尾從后到前開始計算
舉例來說: -10 將會是 Blob 的倒數第十個字節。它的默認值就是它的原始長度(size)
contentType 可選
給新的 Blob 賦予一個新的文檔類型。這將會把它的 type 屬性設為被傳入的值。它的默認值是一個空的字符串
文件分片方法
定義每一個分片文件的大小變量為 chunkSize,通過文件大小 FileSize 和分片大小 chunkSize 得到分片數量 chunks,使用 for 循環和 file.slice() 方法對文件進行分片,序號為 0 - n,和已上傳的切片列表做比對,得到所有未上傳的分片,push 到請求列表 requestList
上傳進度
監聽原生 Javascript 的 XMLHttpRequest 的 progress 事件,這個事件會返回文件已上傳的大小和總大小,可實現上傳進度的變化
博客地址:https://ainyi.com/88