1、【HTML5】Blob對象
(1)寫在前面:本小節主要介紹Blob對象屬性及作用,通過demo介紹blob對象的應用場景。
blob對象:一直以來,JS都沒有比較好的可以直接處理二進制的方法。而blob的存在,允許我們可以通過js直接操作二進制數據。
“一個blob對象就是一個包含有隻讀原始數據的類文件對象。blob對象中的數據並不一定得是JavaScript中的原生形式。file接口基於blob,繼承了blob的功能,並且擴展支持了用戶計算機上的本地文件”
Blob對象可以看作是存放二進制數據的容器,此外還可以通過blob設置二進制數據的MIME類型。
(2)創建blob
方法一:通過構造函數
var blob = new Blob(dataArr:Array<any>,opt:{type:string});
dataArr:數組,包含了要添加到blob對象中的數據,數據可以是任意多個ArrayBuffer,ArrayBufferView,blob或者DOMString對象
opt:對象,用於設置Blob對象的屬性(如MIME類型)
MIME:每一個 URL 都代表着一個資源對象,而當我們請求一個網頁的時候,看似只請求了一個 URI(統一資源標識符),實際上這個網頁可能包含多個 URI,例如圖片資源的 URI 和視頻資源的 URI 等。此時有些瀏覽器爲了加快訪問速度,可能會同時開多個線程去請求 URI。也就是說其實每一個 URI 都發送了一個請求報文。而當我們的瀏覽器要顯示或處理這些資源的時候,我們並不知道其響應的數據是什麼類型的,爲了區分這些資源類型,就需要用到 MIME 了。HTTP 會爲每一個通過 web 傳輸的對象添加上 MIME 類型的數據格式標籤。瀏覽器在讀取到對應的信息後,會調用相應的程序去處理它,任何得到我們想要的結果。
第一種:創建一個裝填DOMString對象的blob對象
image
第二種:創建一個裝填ArrayBuffer對象的Blob對象
image
第三種:創建一個裝填ArrayBufferView對象的Blob對象(ArrayBufferView可基於ArrayBuffer創建,返回值是一個類數組。如下,創建一個8字節的ArrayBuffer,在其上創建一個每個數組元素爲2字節的“視圖”)
image
方法二:通過Blob.slice()
此方法返回一個新的Blob對象,包含了原blob對象中指定範圍內的數據
Blob.slice(start:number,end:number,contentType:string)
start:開始索引,默認爲0
end:截止結束索引(不包括end)
contentType:新blob的MIME類型,默認爲空字符串
image
方法三:通過canvas.toBlob()
var canvas = document.getElementById("canvas");
canvas.toBlob(function(blob){
console.log(blob);
});
2、應用場景
前面提到,file接口繼承blob,繼承了blob的功能並進行了擴展,故我們可以像使用Blob一樣使用File對象
分片上傳
通過Blob.slice方法,可以將大文件分片,輪循向後臺提交各文件片段,即可實現文件的分片上傳。
分片上傳邏輯如下:
獲取要上傳文件的File對象,根據chunk(每片大小)對文件進行分片
通過post方法輪循上傳每片文件,其中url中拼接querystring用於描述當前上傳的文件信息;post body中存放本次要上傳的二進制數據片段
接口每次返回offset,用於執行下次上傳
下面是分片上傳的簡單實現:
initUpload();//初始化上傳functioninitUpload(){
var chunk = 100 * 1024; //每片大小 var input = document.getElementById("file"); //input file input.onchange = function(e){
var file = this.files[0];
var query = {};
var chunks = [];
if (!!file) {
var start = 0;
//文件分片 for (var i = 0; i < Math.ceil(file.size / chunk); i++) {
var end = start + chunk;
chunks[i] = file.slice(start , end);
start = end;
}
// 採用post方法上傳文件 // url query上拼接以下參數,用於記錄上傳偏移 // post body中存放本次要上傳的二進制數據 query = {
fileSize: file.size,
dataSize: chunk,
nextOffset: 0 }
upload(chunks, query, successPerUpload);
}
}
}// 執行上傳functionupload(chunks, query, cb){
var queryStr = Object.getOwnPropertyNames(query).map(key=> {
return key + "=" + query[key];
}).join("&");
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://xxxx/opload?" + queryStr);
xhr.overrideMimeType("application/octet-stream");
//獲取post body中二進制數據 var index = Math.floor(query.nextOffset / query.dataSize);
getFileBinary(chunks[index], function(binary){
if (xhr.sendAsBinary) {
xhr.sendAsBinary(binary);
} else {
xhr.send(binary);
}
});
xhr.onreadystatechange = function(e){
if (xhr.readyState === 4) {
if (xhr.status === 200) {
var resp = JSON.parse(xhr.responseText);
// 接口返回nextoffset // resp = { // isFinish:false, // offset:100*1024 // } if (typeof cb === "function") {
cb.call(this, resp, chunks, query)
}
}
}
}
}// 每片上傳成功後執行functionsuccessPerUpload(resp, chunks, query){
if (resp.isFinish === true) {
alert("上傳成功");
} else {
//未上傳完畢 query.offset = resp.offset;
upload(chunks, query, successPerUpload);
}
}// 獲取文件二進制數據functiongetFileBinary(file, cb){
var reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function(e){
if (typeof cb === "function") {
cb.call(this, this.result);
}
}
}