我正在使用以下代码,使用带有进度指示的fetch
在浏览器中根据用户手势下载较大的内容:
const url = 'https://source.unsplash.com/random';
const response = await fetch(url);
const total = Number(response.headers.get('content-length'));
let loaded = 0;
const reader = response.body.getReader();
let result;
while (!(result = await reader.read()).done) {
loaded += result.value.length;
// Display loaded/total in the UI
}
我在related question中看到了一个片段,这使我相信可以将其简化为:
const url = 'https://source.unsplash.com/random';
const response = await fetch(url);
const total = Number(response.headers.get('content-length'));
let loaded = 0;
for await (const result of response.body.getReader()) {
loaded += result.value.length;
// Display loaded/total in the UI
}
getReader
返回一个ReadableStreamDefaultReader
,它来自Streams API,这是一个Web API以及一个Node API,这使得仅查找与Web相关的信息真的很困难。
在上面的代码段中,代码失败,并显示 response.body.getReader(...)不是函数或返回值不可异步迭代。我检查了对象原型,确实不认为它上面有Symbol.asyncIterator
,所以,难怪浏览器无法对其进行迭代。
因此该问题中的代码一定是错误的,但是现在我想知道, 是否可以采用这样的流并使用for-await
对其进行迭代?我想您需要将其包装在异步生成器中,并以与第一个代码段相似的方式产生块,对吧?
是否有一个现有的或计划中的API使它更加简化,更接近第二个片段,但实际上起作用了?
答案 0 :(得分:1)
ReadableStream本身implements an async iterable
for await (const result of response.body) {
loaded += result.value.length;
// Display loaded/total in the UI
}
答案 1 :(得分:0)
response.body.getReader() .read()
返回的{value:..., done: Boolean}
完全符合asyncIterator
的需求;在ReadableStream本身获得asyncIterator
实现之前,您可以轻松地对其进行填充:
if (!response.body[Symbol.asyncIterator]) {
response.body[Symbol.asyncIterator] = () => {
const reader = response.body.getReader();
return {
next: () => reader.read(),
};
};
}
for await (const result of response.body) {
loaded += result.length;
console.log(((loaded / total) * 100).toFixed(2), '%');
}