JS下大批量異步任務(wù)按順序執(zhí)行的示例分析

這篇文章主要介紹了JS下大批量異步任務(wù)按順序執(zhí)行的示例分析,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

創(chuàng)新互聯(lián)公司服務(wù)項(xiàng)目包括來鳳網(wǎng)站建設(shè)、來鳳網(wǎng)站制作、來鳳網(wǎng)頁制作以及來鳳網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,來鳳網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到來鳳省份的部分城市,未來相信會繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!

前言

最近需要做一個瀏覽器的, 支持大體積文件上傳且要支持?jǐn)帱c(diǎn)續(xù)傳的上傳組件, 本來以為很容易的事情, 結(jié)果碰到了一個有意思的問題:

循環(huán)執(zhí)行連續(xù)的異步任務(wù), 且后一個任務(wù)需要等待前一個任務(wù)的執(zhí)行狀態(tài)

這么說可能有點(diǎn)空泛, 以我做的組件舉例:

這個組件本意是為了上傳大體積視頻, 和支持?jǐn)帱c(diǎn)續(xù)傳, 因?yàn)閯虞m幾個G的視頻不可能直接把文件讀進(jìn)內(nèi)存, 只能分片發(fā)送(考慮到實(shí)際網(wǎng)絡(luò)狀態(tài), 每次發(fā)送大小定在了4MB), 而且這么做也符合斷點(diǎn)續(xù)傳的思路.

組件工作流程如下:

  1. 選定上傳文件后, 從H5原生upload組件里取得文件的blob對象  (同步)

  2. 通過blob對象的slice方法把文件切片  (同步)

  3. 新建一個Filereader對象, 通過Filereader的readAsArrayBuffer方法讀取步驟2中生成的slice  (異步)

  4. 如果步驟3的buffer讀取成功(通過監(jiān)控Filereader的onload事件), 則ajax發(fā)送步驟3中的buffer  (異步)

  5. 如果ajax發(fā)送成功, 且服務(wù)器儲存完成, 會向客戶端發(fā)回一個成功狀態(tài)碼, 如果ajax的response中存在這個狀態(tài)碼, 則進(jìn)行下一次切片發(fā)送  (異步)

從組件工作流程可以發(fā)現(xiàn), 3,4,5中的連續(xù)異步任務(wù), 必須要按順序進(jìn)行, 且每一步任務(wù)間存在相互依賴, 最后還要對這些步驟進(jìn)行多次循環(huán).

如果只是處理單次的連續(xù)異步任務(wù), 通過promise鏈?zhǔn)秸{(diào)用即可, 但是要循環(huán)執(zhí)行這樣的連續(xù)異步任務(wù)讓我想了很久.

后來google了很久也沒發(fā)現(xiàn)解決方案, 無奈下閉門造車了2天, 想出了3套方案, 權(quán)當(dāng)拋磚引玉, 希望各位給出更好建議

3套方案的核心思想相同, 類似觀察者模式, 來控制循環(huán)的進(jìn)行, 區(qū)別在于循環(huán)的實(shí)現(xiàn)不同, 實(shí)際上這3套方案也是我自我否定的過程, 不斷思考更好的方法, 整個組件代碼略長, 在此只挑出問題相關(guān)部分, 且省略錯誤處理部分

方案1

依然以上傳組件舉例

//循環(huán)狀態(tài)標(biāo)記,0為初始狀態(tài),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發(fā)送createReader方法讀取到的Buff
const createXhr = ()=> {
 const xhr= new XMLHttpRequest();
 return new Promise ((reslove, reject)=> {
  ...
  xhr.onreadystatechange= ()=> {
   ...
   //如果readyState == 4,status == 200且服務(wù)器的狀態(tài)碼存在,更改全局標(biāo)記為1
   status = 1;
   reslove()
  }
 })
}

//每一輪循環(huán)開始前都檢查一次全局狀態(tài)標(biāo)記
const checkStatus = ()=> {
 ...
 if (status == 1) {
  loop()
 }
}

//循環(huán)過程的鏈?zhǔn)秸{(diào)用
const loop = ()=> {
 createReader().then(()=> createXhr()).then(()=> checkStatus());
}

方案1是基于初見問題的'想當(dāng)然'解決方法, 碰到異步任務(wù)就promise, 這樣的循環(huán)長鏈調(diào)用, 寫法不優(yōu)雅, 且錯誤調(diào)試異常麻煩, 更爆炸的是因?yàn)殚]包問題, 在循環(huán)執(zhí)行中這些內(nèi)存難以回收, 內(nèi)存消耗急劇增加, 只能等待循環(huán)執(zhí)行完成

方案2

徹底引入觀察者模式, 構(gòu)造一個簡單的EventEmitter, 通過event.on, event.emit的形式完成循環(huán)

//模仿node.js的EventEmitter
class EventEmitter {
 constructor() {
  this.handler = {};
 }
 on(eventName, callback) {
  if (!this.handles){
   this.handles = {};
  }
  if (!this.handles[eventName]) {
   this.handles[eventName] = [];
  }
  this.handles[eventName].push(callback);
 }
 emit(eventName,...arg) {
  if (this.handles[eventName]) {
   for (var i=0;i<this.handles[eventName].length;i++) {
    this.handles[eventName][i](...arg);
   }
  }
 }
 }

let ev= new EventEmitter();
...
//監(jiān)聽createReader事件,如果讀取buffer成功就觸發(fā)toajax事件來上傳切片
ev.on('createReader', ()=> {
 let reader = new Filereader();
 ...
 reader.onload = ()=> {
  ev.emit('toajax')
 }
})

//監(jiān)聽toajax事件,如果上傳成功,就觸發(fā)createReader事件開始讀取下一切片
ev.on('toajax', ()=> {
 let xhr= new XMLHttpRequest();
 ...
 xhr.onreadystatechange = ()=> {
 //如果readyState == 4,status == 200且服務(wù)器的狀態(tài)碼存在
  ev.emit('createReader')
 }
})

方案2徹底貫徹'事件', 代碼語義更自然, 錯誤調(diào)試也比方案1更為簡單, 但內(nèi)存泄漏問題依然存在

方案3

方案3, 回歸方案1的狀態(tài)管理方式, 但是通過setInterval方法來實(shí)現(xiàn)循環(huán).

//全局狀態(tài)標(biāo)記
let status = 0;

//讀取切片
const createReader = ()=> {
 let reader = new Filereader();
 ...
 reader.onload = ()=>status = 1
}

//上傳切片
const createXhr = ()=> {
 let xhr= new XMLHttpRequest();
 ...
 xhr.onreadystatechange = ()=> {
  ...
  //如果readyState == 4,status == 200且服務(wù)器的狀態(tài)碼存在
  status = 2
 }
}

/* 設(shè)置一個間隔時間極短的計(jì)時器,根據(jù)status決定下一步的任務(wù),
* 上傳完成后定時器自動清除自己
* 另外有判斷文件是否上傳完成的方法,這里就不寫了
*/
let timer = setInterval(()=> {
 if (status == 2) {
  createReader();
 } else if (status == 1) {
  createXhr();
 } else if (status == 3) {
  clearInterval(timer);
 }
},10)

不可否認(rèn), 方案3看上去很low, 如果追求極致的執(zhí)行效率, 方案3無疑是最蠢的辦法, 但是方案三相當(dāng)于把異步任務(wù)轉(zhuǎn)化為了同步任務(wù), 語義簡潔, 且沒有上面2種方法的內(nèi)存泄漏問題.

方案3本質(zhì)上是把while (true)改寫成了setInterval, 因?yàn)閣hile true會阻塞線程, 各種異步事件的回調(diào)也會被一同阻塞, 所以選擇了setInterval

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“JS下大批量異步任務(wù)按順序執(zhí)行的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關(guān)知識等著你來學(xué)習(xí)!

分享題目:JS下大批量異步任務(wù)按順序執(zhí)行的示例分析
分享網(wǎng)址:http://m.kartarina.com/article6/pphsog.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)建站用戶體驗(yàn)建站公司App設(shè)計(jì)靜態(tài)網(wǎng)站網(wǎng)站內(nèi)鏈

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站建設(shè)
主站蜘蛛池模板: 久久精品中文无码资源站| 精品无码国产自产拍在线观看蜜 | 少妇人妻偷人精品无码视频| 亚洲国产精品无码专区影院| 人妻无码一区二区不卡无码av| 乱人伦人妻中文字幕无码| 中文字幕久无码免费久久| 精品无码成人片一区二区98 | 中文字幕日产无码| 亚洲一级特黄无码片| 精品久久亚洲中文无码| 亚洲日韩中文无码久久| 最新亚洲人成无码网站| 亚洲性无码一区二区三区| 亚洲爆乳无码一区二区三区| 少妇无码?V无码专区在线观看| 少妇伦子伦精品无码STYLES| 中文字幕丰满乱孑伦无码专区| 精品无码中出一区二区| 性虎精品无码AV导航| 久久久久久无码Av成人影院 | 日韩精品人妻系列无码专区| 亚洲一本大道无码av天堂| 免费无码肉片在线观看| 在人线av无码免费高潮喷水| 久久国产亚洲精品无码| 亚洲av日韩av高潮潮喷无码 | 精品久久无码中文字幕| 无码精品人妻一区二区三区人妻斩 | 无码粉嫩虎白一线天在线观看| 亚洲AV无码成人专区片在线观看 | 亚洲AV无码精品无码麻豆| 久久av高潮av无码av喷吹| 日韩AV片无码一区二区不卡| 亚洲av中文无码字幕色不卡| 亚洲av无码兔费综合| 在线看片无码永久免费aⅴ| 无码丰满熟妇浪潮一区二区AV | 亚洲 无码 在线 专区| 无码无套少妇毛多69XXX| 国产在线拍揄自揄拍无码视频|