JavaScript 學習筆記 之 異步(二)

併發

我們在開發過程中經常會遇到的一個情況是,兩個事件同時執行

比如在實現一個懶加載的界面的時候

用戶滾動頁面,觸發一個ajax請求

當用戶滾動頁面足夠快的時候

發起一個ajax請求的事件可能會與返回ajax響應的事件同時(同一時間段內,並不需要在同一時刻)執行

 

像這樣(至少)兩個事件或者說"進程"同時執行就出現了併發

但在JavaScript中,它們的事件是在事件循環隊列中依次運行的

單線程事件循環是併發的一種形式

 

非交互

當併發執行的多個"進程"在同一個程序內的任務彼此不相關時

就不一定需要交互

因爲進程間沒有相互影響,執行的先後順序帶來的不確定性是完全可以接收的

 

交互

更常見的情況是需要交互進行協調來避免競爭態的出現

比如A進程對data進行+1操作

B進程對data進行*2操作

這時候先執行A進程和先執行B進程會導致結果很大的不同

這種不確定性就是一個競態bug

所以我們可以通過協調交互順序來處理這樣的bug

例如設定一些判斷條件來確保運行順序

 

協作

還有一種併發合作方式,成爲併發協作

這裏的目標是取到一個長期運行的"進程"

將其分割爲多個步驟或者多批任務

使得其他併發"進程"有機會進入到事件循環中

 

例如一個運算量非常龐大的進程

需要處理1000萬條數據

這樣的進程運行時,其他代碼都不能運行,包括不能有其他的函數調用或者UI刷新

甚至連滾動,輸入,點擊之類的用戶事件也無法運行

因此我們可以將這個進程分成很多份

一次只處理1000條數據

然後利用setTimeout(..0)(hack)進行異步調度

也就是下一次處理事件放在當前事件循環的結尾處

來確保事件循環中其他事件能夠運行

 

嚴格來說,setTimeout(..0)並不直接把項目插入到事件循環隊列,而是在有機會的時候插入

因此兩個連續的setTimeout(..0)並不能保證嚴格按照調用順序處理

比如定時器漂移,在這種情況下,這些事件的順序就不可預測

在Node.js中類似的方法是process.nextTick(..)

儘管他們使用方便,但是沒有直接的方法能夠適應所有的環境來確保異步事件的順序

 

任務

在ES6中,有一個新的概念建立在事件循環隊列之上,叫做任務隊列

這個概念帶來的最大影響可能是Promise的異步特性

舉個簡單的例子來說明這兩者的區別

事件循環隊列類似於排隊排到隊尾的隊列

而任務隊列類似於直接插隊的一個隊列

 

任務和setTimeout(..0)hack的思路類似,但是對順序的保證性更強:儘可能早的到來(也就是插隊)

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章