前言
最近需要做一個瀏覽器的, 支持大體積文件上傳且要支持斷點續傳的上傳組件, 本來以為很容易的事情, 結果碰到了一個有意思的問題:
循環執行連續的異步任務, 且后一個任務需要等待前一個任務的執行狀態
這么說可能有點空泛, 以我做的組件舉例:
這個組件本意是為了上傳大體積視頻, 和支持斷點續傳, 因為動輒幾個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());}
新聞熱點
疑難解答
圖片精選