循环分片上传场景下await与.then的使用差异及实现方案
解决方案
核心思路
要实现循环内分片按顺序上传的.then()写法,本质是利用Promise链式调用的串行执行特性:我们维护一个初始为已完成状态的Promise根节点,每一轮循环都把当前分片的上传逻辑挂载到上一个Promise的.then()回调中,确保前一个分片上传完成后才会触发下一个分片的上传任务。
完整改写代码
const fileReader = new FileReader(); const theFile = f.files[0]; fileReader.onload = (ev) => { const CHUNK_SIZE = 5000; const chunkCount = ev.target.result.byteLength / CHUNK_SIZE; console.log("Read successfully"); const fileName = Math.random() * 1000 + theFile.name; // 初始化Promise链的起点,初始状态为已完成 let uploadChain = Promise.resolve(); for (let chunkId = 0; chunkId < chunkCount + 1; chunkId++) { // 把当前分片任务追加到链上 uploadChain = uploadChain.then(() => { const chunk = ev.target.result.slice( chunkId * CHUNK_SIZE, chunkId * CHUNK_SIZE + CHUNK_SIZE ); // 返回fetch的Promise,让链式调用等待当前上传完成 return fetch("http://localhost:8080/upload", { method: "POST", headers: { "content-type": "application/octet-stream", "content-length": chunk.length, "file-name": fileName, }, body: chunk, }).then(() => { // 上传完成后更新进度,对应原来await之后的逻辑 divOutput.textContent = Math.round((chunkId * 100) / chunkCount, 0) + "%"; }); }); } // 所有分片上传完成后的回调,对应原来循环结束后的逻辑 uploadChain.then(() => { console.log(ev.target.result.byteLength); }); }; fileReader.readAsArrayBuffer(theFile);
注意要点
- 循环中使用
let声明chunkId,利用块级作用域特性保证每个分片回调里拿到的分片ID正确,避免异步回调变量污染问题 - 每个
.then()回调必须返回当前fetch产生的Promise,否则链式调用不会等待上传完成就会执行下一个任务,导致分片顺序混乱 - 所有分片全部上传完成后的逻辑可以挂载到最终的
uploadChain的.then()回调中执行
内容的提问来源于stack exchange,提问作者Vehbi
相关产品推荐
相关产品推荐

