javascript關於異步執行不按順序解決方案


參考:《你不知道的JavaScript中卷》異步1.4節

案例分析:

比如執行懶加載時候,onscroll 事件觸發多次事件時候會調用多次 ajax 回調事件,由於每個事件返回先后次序並不能保證和觸發前一致,所以在數據響應返回后所添加的數據順序就很在 push 到數組上順序不一致。

例子1:

var res = [];
     function response(data) {
         res.push( data );
}
// ajax(..)是某個庫中提供的某個Ajax函數 
ajax( "http://some.url.1", response ); 
ajax( "http://some.url.2", response );

這里的並發“進程”是這兩個用來處理 Ajax 響應的 response() 調用。它們可能以任意順 序運行。

我們假定期望的行為是 res[0] 中放調用 "http://some.url.1" 的結果,res[1] 中放調用 "http://some.url.2" 的結果。有時候可能是這樣,但有時候卻恰好相反,這要視哪個調 用先完成而定。

這種不確定性很有可能就是一個競態條件 bug。

解決辦法

 

 1 var res = [];
 2 function response(data) {
 3           if (data.url == "http://some.url.1") {
 4               res[0] = data;
 5           }
 6           else if (data.url == "http://some.url.2") {
 7               res[1] = data;
 8           } 
 9 }
10 // ajax(..)是某個庫中提供的某個Ajax函數 
11 ajax( "http://some.url.1", response ); 
12 ajax( "http://some.url.2", response );    

不管哪一個 Ajax 響應先返回,我們都要通過查看 data.url(當然,假定從服務器總會返 回一個!)判斷應該把響應數據放在 res 數組中的什么位置上。res[0] 總是包含 "http:// some.url.1" 的結果,res[1] 總是包含 "http://some.url.2" 的結果。通過簡單的協調,就 避免了競態條件引起的不確定性。

 

例子2:

 1 var a, b;
 2       function foo(x) {
 3           a = x * 2;
 4           baz(); 
 5       }
 6       function bar(y) {
 7          b = y * 2;
 8          baz(); 
 9       }
10       function baz() {
11          console.log(a + b);
12       }
13 // ajax(..)是某個庫中的某個Ajax函數 
14 ajax( "http://some.url.1", foo ); 
15 ajax( "http://some.url.2", bar );

在這個例子中,無論 foo() 和 bar() 哪一個先被觸發,總會使 baz() 過早運行(a 或者 b 仍處 於未定義狀態);但對 baz() 的第二次調用就沒有問題,因為這時候 a 和 b 都已經可用了。

要解決這個問題有多種方法。這里給出了一種簡單方法:
 1 var a, b;
 2 function foo(x) {
 3          a = x * 2;
 4          if (a && b) {
 5              baz();
 6          } 
 7 }
 8 function bar(y) {
 9          b = y * 2;
10          if (a && b) {
11              baz();
12          } 
13 }
14 function baz() {
15          console.log( a + b );
16 }
17 // ajax(..)是某個庫中的某個Ajax函數 
18 ajax( "http://some.url.1", foo );
19 ajax( "http://some.url.2", bar );

包裹baz()調用的條件判斷if (a && b)傳統上稱為門(gate),我們雖然不能確定a和b 到達的順序,但是會等到它們兩個都准備好再進一步打開門(調用 baz())。

 

 

更多相關細節可參考:《你不知道的JavaScript中卷》異步 章節

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM