Javascript异步执行不按顺序解决方案
案例分析:
比如执行懒加载时候,onscroll事件触发多次事件时候会调用多次ajax回调事件,由于每个事件返回先后次序并不能保证和触发前一致,所以在数据响应返回后所添加的数据顺序就很在push到数组上顺序不一致。
例子1:
varres=[];
functionresponse(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。
解决办法
varres=[];
functionresponse(data){
if(data.url=="http://some.url.1"){
res[0]=data;
}
elseif(data.url=="http://some.url.2"){
res[1]=data;
}
}
//ajax(..)是某个库中提供的某个Ajax函数
ajax("http://some.url.1",response);
ajax("http://some.url.2",response);
不管哪一个Ajax响应先返回,我们都要通过查看data.url(当然,假定从服务器总会返回一个!)判断应该把响应数据放在res数组中的什么位置上。res[0]总是包含"http://some.url.1"的结果,res[1]总是包含"http://some.url.2"的结果。通过简单的协调,就避免了竞态条件引起的不确定性。
例子2:
vara,b;
functionfoo(x){
a=x*2;
baz();
}
functionbar(y){
b=y*2;
baz();
}
functionbaz(){
console.log(a+b);
}
//ajax(..)是某个库中的某个Ajax函数
ajax("http://some.url.1",foo);
ajax("http://some.url.2",bar);
在这个例子中,无论foo()和bar()哪一个先被触发,总会使baz()过早运行(a或者b仍处于未定义状态);但对baz()的第二次调用就没有问题,因为这时候a和b都已经可用了。
要解决这个问题有多种方法。这里给出了一种简单方法:
vara,b;
functionfoo(x){
a=x*2;
if(a&&b){
baz();
}
}
functionbar(y){
b=y*2;
if(a&&b){
baz();
}
}
functionbaz(){
console.log(a+b);
}
//ajax(..)是某个库中的某个Ajax函数
ajax("http://some.url.1",foo);
ajax("http://some.url.2",bar);
包裹baz()调用的条件判断if(a&&b)传统上称为门(gate),我们虽然不能确定a和b到达的顺序,但是会等到它们两个都准备好再进一步打开门(调用baz())。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。