stream 数据流
除了返回Promise
对象,Fetch API 还有一个特点,就是数据传送是以数据流(stream)的形式进行的。对于大文件,数据是一段一段得到的。
response.text().then(function (responseText) {
console.log(responseText);
}
上面代码中,text()
就是一个数据流读取器。
Fetch API 提供以下五个数据流读取器。
.text()
:返回字符串.json()
:返回JSON对象.formData()
:返回FormData
对象.blob()
:返回blob
对象.arrayBuffer()
:返回二进制数组ArrayBuffer
对象
数据流只能读取一次,一旦读取,数据流就空了。再次读取就不会得到结果。解决方法是在读取之前,先使用.clone()
方法,复制一份一模一样的副本。
var url = 'LargeFile.txt';
var progress = 0;
var contentLength = 0;
fetch(url).then(function (response) {
// 本次请求总的数据长度
contentLength = response.headers.get('Content-Length');
var getStream = function (reader) {
// ...
};
return getStream(response.body.getReader());
})
.catch(function (error) {
console.log(error);
});
上面代码中,response.body.getReader()
返回的就是数据流之中的一段。处理数据流的getStream
函数代码如下。
var progress = 0;
var contentLength = 0;
var getStream = function (reader) {
return reader.read().then(function (result) {
// 如果数据已经读取完毕,直接返回
if (result.done) {
return;
}
// 取出本段数据(二进制格式)
var chunk = result.value;
var text = '';
// 假定数据是UTF-8编码,前三字节是数据头,
// 而且每个字符占据一个字节(即都为英文字符)
for (var i = 3; i < chunk.byteLength; i++) {
text += String.fromCharCode(chunk[i]);
}
// 将本段数据追加到网页之中
document.getElementById('content').innerHTML += text;
// 计算当前进度
progress += chunk.byteLength;
console.log(((progress / contentLength) * 100) + '%');
// 递归处理下一段数据
return getStream(reader);
};
};
上面这样的数据流处理,可以提高网站性能表现,减少内存占用,对于请求大文件或者网速慢的场景相当有用。传统的XMLHTTPRequest
对象不支持数据流,所有的数据必须放在缓存里,等到全部拿到后,再一次性吐出来。