我正在尝试捕获Fetch请求的下载进度,并将其用于改变进度条的宽度。我查看了ProgressEvent.lengthComputable作为潜在解决方案,但不确定是否可以与Fetch API一起使用。
我正在尝试捕获Fetch请求的下载进度,并将其用于改变进度条的宽度。我查看了ProgressEvent.lengthComputable作为潜在解决方案,但不确定是否可以与Fetch API一起使用。
const elStatus = document.getElementById('status');
function status(text) {
elStatus.innerHTML = text;
}
const elProgress = document.getElementById('progress');
function progress({loaded, total}) {
elProgress.innerHTML = Math.round(loaded/total*100)+'%';
}
async function main() {
status('downloading with fetch()...');
const response = await fetch('https://fetch-progress.anthum.com/30kbps/images/sunrise-baseline.jpg');
const contentLength = response.headers.get('content-length');
const total = parseInt(contentLength, 10);
let loaded = 0;
const res = new Response(new ReadableStream({
async start(controller) {
const reader = response.body.getReader();
for (;;) {
const {done, value} = await reader.read();
if (done) break;
loaded += value.byteLength;
progress({loaded, total})
controller.enqueue(value);
}
controller.close();
},
}));
const blob = await res.blob();
status('download completed')
document.getElementById('img').src = URL.createObjectURL(blob);
}
main();
<div id="status"> </div>
<h1 id="progress"> </h1>
<img id="img" />
参考自此处
Accept-Encoding: gzip
标头,服务器响应如下 - Content-Type: application/json
Content-Encoding: gzip
Content-Length: xxx
那么,在从 body reader 读取时,长度 xxx
将比块的总长度小得多。基本上,在某个点之后,loaded
将比 total
多。因为 content-length
标头包含压缩响应的大小。但是,loaded
是解压缩后计算的块大小。 - ecthienderasync function* streamAsyncIterable(stream) {
const reader = stream.getReader()
try {
while (true) {
const { done, value } = await reader.read()
if (done) return
yield value
}
} finally {
reader.releaseLock()
}
}
然后,您可以使用 for await...of
循环:
const response = await fetch(url)
let responseSize = 0
for await (const chunk of streamAsyncIterable(response.body)) {
responseSize += chunk.length
}
responseSize
是 响应大小!并不一定是下载大小!有什么区别?如果没有 content-encoding
(gzip
,br
,...),则没有区别。但如果应用了压缩,则最终的下载大小将是压缩数据的大小(相同的 content-length
),而最终的响应大小将是未压缩数据的大小。for await
循环中读取(和连接)totalBytes
。然后,您需要将totalBytes
转换为string
,然后再进行JSON.parse()
。不要将每个chunk
都转换为string
(然后连接string
)!这会导致一些问题,因为多字节字符可能位于两个连续块的边界处。 - Mir-Ismaili你可以使用axios代替
import axios from 'axios'
export async function uploadFile(file, cb) {
const url = `//127.0.0.1:4000/profile`
try {
let formData = new FormData()
formData.append("avatar", file)
const data = await axios.post(url, formData, {
onUploadProgress: (progressEvent) => {
console.log(progressEvent)
if (progressEvent.lengthComputable) {
let percentComplete = progressEvent.loaded / progressEvent.total;
if (cb) {
cb(percentComplete)
}
}
}
})
return data
} catch (error) {
console.error(error)
}
}