非交互:
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) { // 永远执行
// 一次tick
if( 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