前言
最近需要做一个浏览器的, 支持大体积文件上传且要支持断点续传的上传组件, 本来以为很容易的事情, 结果碰到了一个有意思的问题:
循环执行连续的异步任务, 且后一个任务需要等待前一个任务的执行状态
这么说可能有点空泛, 以我做的组件举例:
这个组件本意是为了上传大体积视频, 和支持断点续传, 因为动辄几个G的视频不可能直接把文件读进内存, 只能分片发送(考虑到实际网络状态, 每次发送大小定在了4MB), 而且这么做也符合断点续传的思路.
组件工作流程如下:
从组件工作流程可以发现, 3,4,5中的连续异步任务, 必须要按顺序进行, 且每一步任务间存在相互依赖, 最后还要对这些步骤进行多次循环.
如果只是处理单次的连续异步任务, 通过promise链式调用即可, 但是要循环执行这样的连续异步任务让我想了很久.
后来google了很久也没发现解决方案, 无奈下闭门造车了2天, 想出了3套方案, 权当抛砖引玉, 希望各位给出更好建议
3套方案的核心思想相同, 类似观察者模式, 来控制循环的进行, 区别在于循环的实现不同, 实际上这3套方案也是我自我否定的过程, 不断思考更好的方法, 整个组件代码略长, 在此只挑出问题相关部分, 且省略错误处理部分
方案1
依然以上传组件举例
//循环状态标记,0为初始状态,1为正常,2为出错let status = 0;/* 新建Filereader,读取文件切片,返回一个promise* 把读取成功的arraybuffer通过reslove传出*/const createReader = ()=> { return new Promise ((reslove, reject)=> { let reader = new Filereader(); ... reader.onload = ()=> { reslove(reader.result) } reader.onerror = ()=> reject() })}// ajax发送createReader方法读取到的Buffconst createXhr = ()=> { const xhr= new XMLHttpRequest(); return new Promise ((reslove, reject)=> { ... xhr.onreadystatechange= ()=> { ... //如果readyState == 4,status == 200且服务器的状态码存在,更改全局标记为1 status = 1; reslove() } })}//每一轮循环开始前都检查一次全局状态标记const checkStatus = ()=> { ... if (status == 1) { loop() }}//循环过程的链式调用const loop = ()=> { createReader().then(()=> createXhr()).then(()=> checkStatus());}
新闻热点
疑难解答
图片精选