# [知識篇]WebAPIs - Blob

在WebRTC APIs - RTCDataChannel中,傳輸數據時只能傳輸BlobArrayBuffer,剛好藉此機會,來了解開發時常用於檔案上傳處理(如照片上傳等)的兩種物件。

# Blob

Blob(Binary large Object)物件,主要目的是提供可代表及操作與儲存 JavaScript native 以外的格式,所以能夠讀取binary data,例如利用Blob讀寫照片檔,但其保存的數據是不可改寫的(immutable)。

而我們常用在<input type=file>來拿到的File物件也是一種特殊的Blob物件,其繼承了Blob的屬性。

Blob物件屬性:

  • size: 表示儲存的資料,總共佔了多少位元(byte)。
  • type: 表示儲存的資料格式(MIME type)。

# 範例

這邊會舉例幾個常用情境:

  • 透過File來讀取使用者系統中的資料。
const fileInput = document.querySelector('input[type=file]')
const { files } = fileInput

console.log(files)
  • 透過FileReader來讀取Blob中的內容,並且能轉換成text/ArrayBuffer/...等格式。
const blob = new Blob(['<div><h1>Hello World</h1></div>'])

const getFileLoad = event => console.log('FileRead.onload ', event.target.result)
const fileReader = new FileReader();

// 成功load資料後觸發
fileReader.addEventListener('load', getFileLoad);

// 讀取並轉成ArrayBuffer
fileReader.readAsArrayBuffer(blob);

這邊實例化一個Blob物件,其建構式有兩個參數:

var newBlob = new Blob(array, options);

  • array: 可以是ArrayBuffer, ArrayBufferView, Blob, USVString等這些物件組成的陣列。

  • options

    • type: 定義資料的MIME格式
  • 透過URL.createObjectUrl(Blob)來產生對應的Blob url,用於Browser上的a tag或是img src,便於下載或是顯示圖片。

const blob = new Blob([JSON.stringify({hello: 'world'})], {type: 'application/json'})
const url = URL.createObjectURL(blob)

// 模擬檔案下載
const aTag = document.createElement('a')
aTag.href = url
aTag.download = 'JsonFile'
aTag.click()

// 清掉暫存
aTag.href = '';
URL.revokeObjectURL(url);

注意:

  • 透過URL.createObjectUrl創建url時,如果沒有要使用了,要記得URL.revokeObjectURL(),因為這是靜態方式,所以使用時會暫存,沒有清除的話會一直佔用著記憶體。

  • Blob URL只能夠在同個瀏覽器中使用,內容只有包含瀏覽器存放Blob object的參考位置,方便某些API運用(如上傳時圖片預覽),並不包含實際檔案數據,所以不像Data URL(base64)一樣有保存實際完整數據。

  • 利用Blob.prototype.slice()拆分檔案數據分次傳送。

const chunkSize = 10
let offset = 0
let blob = new Blob(['<div><h1>Hello World</h1></div>'])

const getFileLoad = event => {
  offset += event.target.result.byteLength; // ArrayBuffer的單位是byteLength
  console.log(offset)
  if (offset < blob.size) {
    readSlice(offset);
  }
}
const fileReader = new FileReader();

// 成功load資料後觸發
fileReader.addEventListener('load', getFileLoad);

// 切分後讀取並轉成ArrayBuffer
const readSlice = o => {
  const chunk = blob.slice(offset, o + chunkSize);
  fileReader.readAsArrayBuffer(chunk);
};
readSlice(0)

利用Blob.prototype.slice()複製的方式,達到切分的功能。

var newBlob = blob.slice(start, end, contentType);

# 特性

從幾個範例演示下來,可以發現Blob有幾個好處

  • 使網頁透過js能夠讀寫使用者指定的檔案。
  • 上傳比較大的檔案時,也能做切分,分次上傳。
  • 可以轉成ArrayBuffer儲存成binary data。
  • 透過createObjectURL的方式,轉成Blob URL後只要是能使用url的地方都能夠傳入(a href, img src...等),使用彈性增加。

# 支援度

參考:

# 總結

本章了解到:

  • Blob適合用來操作文件檔案。
  • Blob物件的內容必須透過FileReader讀取。
  • 搭配FileReader能進行將Blob轉換成text/ArrayBuffer/DataUrl及切分傳輸..等用途。
  • 經由URL.createObjectURL轉成Blob URL。

# 參考