非交互:
var res = {};function foo(results) {res.foo = results;
}function bar(results) {res.bar = results;
}ajax( "http://some.url.1", foo);
ajax( "http://some.url.2", bar);// foo和bar彼此不相關,誰先執行都無所謂..不影響執行結果
交互:
// 交互1:執行順序影響參數位置var res = [];function response(data) {res.push(data);
}ajax( "http://some.url.1", response);
ajax( "http://some.url.2", response);// ajax請求的結果會放到res中,根據先后順序有可能產生我們不需要的結果.,
// 如我們想把第一個ajax的結果放到res[0]中,第二個ajax的結果放到res[1]中.但異步的不確定性,有可能先執行第2個ajax.
// 可以對response作如下的改變:var res = [];function response(data) {if(data.url === "ajax1") {res[0] = data;}else {if(data.url === "ajax2") {res[1] =data;}}
}ajax("http://some.url.1",response);
ajax("http://some.url.2",response);// 注:data.url是假設從服務器返回的標識字段.
// 交互2:參數缺失
var a, b;function foo(x) {a = x * 2;baz();
}function bar(y) {b = y * 2;baz();
}function baz() {console.log( a + b);
}ajax("http://some.url.1", foo);
ajax("http://some.url.2", bar);// 在兩個ajax全部完成前(或只有1個ajax請求完成時,比如ajax1完成)會出現參數丟失的現象:即ajax1完成了,執行foo()方法.
// 先得到a,然后調用baz()方法,此時是沒有b(undefined)的.
// 改進baz如下:function baz() {if( a && b ) {console.log(a + b);}
}
// 交互3:門閂:只執行第一個完成的函數
var a;function foo(x) {a = x * 2;baz();
}function bar(x) {a = x / 2;baz();
}function baz() {console.log(a);
}ajax( "http://some.url.1", foo );
ajax( "http://some.url.2", bar );// 后面執行的會覆蓋前面的a
// 我們想a在第一次執行時就確定,改進如下:
function foo(x) {if(!a) {a = x * 2;baz();}
}function bar(x) {if(!a) {a = x / 2;baz();}
}
協作:
var res = [];function response(data) {res = res.concat( data.map( function(val) {return val * 2;}));
}ajax( "http://some.url.1", response);
ajax( "http://some.url.2", response);// 上述會將ajax請求的數據,全部翻倍..表面上看去沒有問題...考慮1000萬條記錄
// 你會發現,一個回調函數會占用很長的時間,導致期間用戶什么都不能做.what a pain..
// 改進如下:
function reponse(data) {var chunk = data.splice(0, 1000);res = res.concat( chunk.map( function (val) { return val * 2;}) );if (data.length > 0) {setTimeout( function () {response(data);}, 0 );}
}// 將大數據量切成小塊.然后使用setTimeout放入到事件循環隊列.這樣就可以在處理數據的時候,同時讓其他等待的事件有機會運行.
// 事件循環隊列的偽代碼如下:var eventLoop = [];
var event;while(true) { // 永遠執行// 一次tickif( eventLoop.length > 0) {event = event.Loop.shift();try {event();}catch (err) {reportError(err);}}
}// setTimeout({},0)相當于把response(data)推進了eventLoop.而事件循環是一個一個執行的.
任務:
// ES6一個建立在事件循環隊列之上的新概念,任務隊列.
console.log("A");setTimeout( function () {console.log( "B" );
}, 0 );// 理論上的"任務API"
schedule( function(){console.log( "C" );schedule( function() {console.log( "D" );});
});
// 任務隊列是事件循環每一個tick之前執行的.
參考《你不知道的JavaScript》(中卷)P150~P156