非交互:
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