我正在寻找一个客户端唯一的JavaScript解决方案,可以接收一个大的二进制文件从HTTP服务器到我的web客户端以流媒体的方式,这样我就可以立即响应,只要我得到数据包,而不必等待所有它们加载到内存中,我甚至可以丢弃处理后的数据,以减少内存占用。
我在网上搜索,发现似乎不可能通过XMLHttpRequest,因为两个原因(引用自本文),
- XHR阻止在请求完成之前访问二进制响应(带有arraybuffer响应类型)数据。
- XHR响应本质上是一个大缓冲区,随着响应数据的传入而线性增长,这意味着它不能被垃圾收集。
我想知道这是否可以通过websocket实现,是否有任何好的开源已经解决了这个问题?我发现了一些似乎相关的,比如obe .js和Binary.js,但它要么处理JSON流,要么需要服务器端支持。
使用XMLHttpRequest不能满足我的所有请求。但是,使用一些技巧,我可以读取块二进制数据,一旦它到达。一般来说,将minetype重写为'text/plain;charset=x-user-defined',它将二进制数据作为文本流,一旦一个包准备好了,我就可以得到它并将其转换为arrayBuffer。
var xhr = new XMLHttpRequest();
var streamOffset = 0;
xhr.overrideMimeType('text/plain; charset=x-user-defined');
xhr.open("GET", url, true);
xhr.send();
xhr.onreadystatechange = function () {
var textBuffer = xhr.responseText;
var arrayBuffer = textToArrayBuffer(textBuffer, streamOffset);
}
function textToArrayBuffer(textBuffer, startOffset) {
var len = textBuffer.length - startOffset;
var arrayBuffer = new ArrayBuffer(len);
var ui8a = new Uint8Array(arrayBuffer, 0);
for (var i = 0, j = startOffset; i < len; i++, j++)
ui8a[i] = (textBuffer.charCodeAt(j) & 0xff);
return arrayBuffer;
}
虽然,通过这种方式我可以以流的方式获得二进制数据,但在处理每个块之后,直到请求完成才可以丢弃它。无论如何,这使我有机会在二进制数据到达时立即处理它。
现在,你可以通过使用Fetch API来实现。
fetch()
的结果包含一个名为body
的属性,该属性是一个可读流,可用于读取结果。
fetch('https://example.fake/movies.csv')
.then((fetchedData) => {
const reader = fetchedData.body.getReader();
readChunks(reader);
});
function readChunks(reader) {
reader.read().then(({ done, value }) => {
if (done) {
console.log('done reading', value);
return;
}
console.log('read chunk', value);
readChunks(reader);
});
}