亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

淺談關(guān)于JS下大批量異步任務(wù)按順序執(zhí)行解決方案一點(diǎn)思考

 更新時(shí)間:2019年01月08日 14:33:57   作者:終極蛇皮可達(dá)鴨  
這篇文章主要介紹了淺談關(guān)于JS下大批量異步任務(wù)按順序執(zhí)行解決方案一點(diǎn)思考,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧

前言

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

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

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

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

組件工作流程如下:

  1. 選定上傳文件后, 從H5原生upload組件里取得文件的blob對(duì)象  (同步)
  2. 通過blob對(duì)象的slice方法把文件切片  (同步)
  3. 新建一個(gè)Filereader對(duì)象, 通過Filereader的readAsArrayBuffer方法讀取步驟2中生成的slice  (異步)
  4. 如果步驟3的buffer讀取成功(通過監(jiān)控Filereader的onload事件), 則ajax發(fā)送步驟3中的buffer  (異步)
  5. 如果ajax發(fā)送成功, 且服務(wù)器儲(chǔ)存完成, 會(huì)向客戶端發(fā)回一個(gè)成功狀態(tài)碼, 如果ajax的response中存在這個(gè)狀態(tài)碼, 則進(jìn)行下一次切片發(fā)送  (異步)

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

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

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

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

方案1

依然以上傳組件舉例

//循環(huán)狀態(tài)標(biāo)記,0為初始狀態(tài),1為正常,2為出錯(cuò)
let status = 0;

/* 新建Filereader,讀取文件切片,返回一個(gè)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)長(zhǎng)鏈調(diào)用, 寫法不優(yōu)雅, 且錯(cuò)誤調(diào)試異常麻煩, 更爆炸的是因?yàn)殚]包問題, 在循環(huán)執(zhí)行中這些內(nèi)存難以回收, 內(nèi)存消耗急劇增加, 只能等待循環(huán)執(zhí)行完成

方案2

徹底引入觀察者模式, 構(gòu)造一個(gè)簡(jiǎn)單的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事件來(lái)上傳切片
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徹底貫徹'事件', 代碼語(yǔ)義更自然, 錯(cuò)誤調(diào)試也比方案1更為簡(jiǎn)單, 但內(nèi)存泄漏問題依然存在

方案3

方案3, 回歸方案1的狀態(tài)管理方式, 但是通過setInterval方法來(lái)實(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è)置一個(gè)間隔時(shí)間極短的計(jì)時(shí)器,根據(jù)status決定下一步的任務(wù),
* 上傳完成后定時(shí)器自動(dòng)清除自己
* 另外有判斷文件是否上傳完成的方法,這里就不寫了
*/
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無(wú)疑是最蠢的辦法, 但是方案三相當(dāng)于把異步任務(wù)轉(zhuǎn)化為了同步任務(wù), 語(yǔ)義簡(jiǎn)潔, 且沒有上面2種方法的內(nèi)存泄漏問題.

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

總結(jié)

當(dāng)時(shí)還嘗試過使用Object.defineProperty方法給status 綁一個(gè)set方法, 通過每次給status set新值的時(shí)候來(lái)判斷循環(huán), 但是發(fā)現(xiàn)這樣做依然像是鏈?zhǔn)秸{(diào)用, 一樣存在內(nèi)存泄漏問題, 這里就不寫了.

說(shuō)實(shí)話, 這3個(gè)方案感覺都有很大缺陷, 甚至可以說(shuō)粗淺, 本人入坑前端2個(gè)月, 眼界有限無(wú)可避免, google無(wú)門后, 想到社區(qū)來(lái)求助, 希望老哥們提供更好的思路.

最后掛上文中提到的上傳插件, 因?yàn)楦杏X還有缺陷就沒封裝, 只做了個(gè)demo(前端上傳插件用的方案2, 后端拼接文件切片用的方案3)

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • JS實(shí)現(xiàn)隱藏同級(jí)元素后只顯示JS文件內(nèi)容的方法

    JS實(shí)現(xiàn)隱藏同級(jí)元素后只顯示JS文件內(nèi)容的方法

    這篇文章主要介紹了JS實(shí)現(xiàn)隱藏同級(jí)元素后只顯示JS文件內(nèi)容的方法,可實(shí)現(xiàn)將與js文件的同級(jí)元素全部隱藏,只顯示js文件內(nèi)容的功能,涉及javascript針對(duì)頁(yè)面元素的遍歷與屬性修改相關(guān)技巧,需要的朋友可以參考下
    2016-09-09
  • 手機(jī)安裝GreasyFork油猴js腳本的教程

    手機(jī)安裝GreasyFork油猴js腳本的教程

    Iceraven瀏覽器需要安裝Tampermonkey插件來(lái)安裝GF油猴腳本,本文給大家介紹手機(jī)安裝GreasyFork油猴js腳本的教程,安裝過程給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2021-12-12
  • layer實(shí)現(xiàn)彈窗提交信息

    layer實(shí)現(xiàn)彈窗提交信息

    這篇文章主要為大家詳細(xì)介紹了layer實(shí)現(xiàn)彈窗提交信息的相關(guān)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • Javascript中的幾種URL編碼方法比較

    Javascript中的幾種URL編碼方法比較

    這篇文章主要介紹了Javascript中的幾種URL編碼方法比較,本文對(duì)比了escape()、encodeURI()以及encodeURIComponent()這3種URL編碼方法,需要的朋友可以參考下
    2015-01-01
  • JS實(shí)現(xiàn)控制文本框的內(nèi)容

    JS實(shí)現(xiàn)控制文本框的內(nèi)容

    下面小編就為大家?guī)?lái)一篇JS實(shí)現(xiàn)控制文本框的內(nèi)容。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧
    2016-07-07
  • JavaScript怎樣在刪除前添加確認(rèn)彈出框?

    JavaScript怎樣在刪除前添加確認(rèn)彈出框?

    這篇文章主要介紹了怎樣在刪除前添加確認(rèn)彈出框?下面小編帶大家來(lái)學(xué)習(xí)一下
    2019-05-05
  • js實(shí)現(xiàn)文字頭像的生成代碼

    js實(shí)現(xiàn)文字頭像的生成代碼

    這篇文章主要介紹了js實(shí)現(xiàn)文字頭像的生成的代碼,代碼簡(jiǎn)單易懂,非常不錯(cuò),對(duì)大家的工作或?qū)W習(xí)具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • 一看就懂的i++和++i示例代碼詳解

    一看就懂的i++和++i示例代碼詳解

    這篇文章主要介紹了i++和++i區(qū)別詳解,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03
  • Javascript中的對(duì)象屬性是有序的嗎

    Javascript中的對(duì)象屬性是有序的嗎

    這篇文章主要介紹了Javascript中的對(duì)象屬性是有序的嗎,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-08-08

最新評(píng)論