Ajax异步调用的顺序执行
Posted 狐狸姬
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ajax异步调用的顺序执行相关的知识,希望对你有一定的参考价值。
上次有提到用ajax调用后端接口获取数据,但我最近遇到了一个问题。如果说通过一个接口获取一组列表,列表中的每一个项又要去通过另一个接口查询对应的值,再把第二次得到的值按照第一次获得的列表顺序展现出来,那么应该怎么做呢?
ajax的优点就在于它可以异步调用接口,当一个异步请求发送时,浏览器不会处于锁死、等待的状态,从一个异步请求发送到获取响应结果的期间,浏览器还可以进行其它的操作。但这个特点也意味着如果我们有两个请求,第二个请求需要在第一个请求完成之后执行,这种默认是不行的。因为两个请求的执行是并行的。
我们来举个例子。假设ajax1是从后台请求一组列表,然后我们把列表中的每一项的值alert出来。一般的思路(也可能就我是这样想的,脑子转不过弯来)是在ajax的回调函数中做一个$.each()的遍历,然后在里面写alert。这种情况我这样写应该没什么问题
//接口路径
var url = "";
//查询关键字
var keyword = "";
$.ajax({
url: url,
data: {
key: keyword,
},
type: "get",
dataType: "json",
success: function(data) {
//这边假设接口给的json格式数据
//有一个数组是result,
//result里面每一个object有一个key是name
$.each(data.result, function(i, el) {
alert(el.name);
});
},
error: function(data) {
console.log(data);
}
});
ajax请求success之后执行的这个函数是在获取到值之后进行的,所以这里alert(el.name)的顺序也是按照获取到的data中的顺序。那如果我们把alert这个操作换掉,我们希望根据每一个el.name去查询address怎么办?这时候我的想法是和上文一样。在alert(el.name)的同样位置调用一个函数,这个函数发起一个新的ajax请求,然后在新的ajax的请求成功回调函数中获取到address。这样做也是可行的。(如果有更好的方法请告诉我~)
//接口路径
var url = "";
var urlGetAddress = "";
//查询关键字
var keyword = "";
$.ajax({
url: url,
data: {
key: keyword,
},
type: "get",
dataType: "json",
success: function(data) {
//这边假设接口给的json格式数据
//有一个数组是result,
//result里面每一个object有一个key是name
$.each(data.result, function(i, el) {
//alert(el.name);
getAddress(el.name);
});
},
error: function(data) {
console.log(data);
}
});
function getAddress(name) {
$.ajax({
url: urlGetAddress,
data: {
name: name,
},
type: "get",
dataType: "json",
success: function(data) {
//这里是每个name请求一次
//所以不需要遍历
alert(data.result);
}
});
}
但如果这样写存在问题。每一个name获取address是成功的,但是address的顺序不一定和name的顺序一致。按我们的想法,在第一个ajax遍历结果时我们是按照name的顺序发起第二个ajax请求的。假设name有3个,那么3个分别是按照A,B,C的顺序去请求的。但是B虽然在A之后发起,但是B不会等到A结束再开始。就像两个人跑步,A先开始跑,B在A出发后也开始跑,但是A和B哪个先到终点这是不一定的。如果你不在意A,B,C跑到终点的顺序,只是要这个结果,那请你关掉这篇文章= =。如果我们需要A,B,C到达顺序和出发顺序一致,那我们接着来想想怎么弄。
同步
第一个可能出现的想法是把ajax的async参数改为false。虽然ajax的优点是异步请求,但是也是可以同步的。但是这样在你请求的时候其他js是没办法执行的。对于用户来说就是卡死了。所以这个先放着。
排序
排序这个想法是我现在用的,但是总感觉不太好。既然没有办法控制A,B,C到达终点的顺序,那我们可以在他们到达之后,根据他们的出发顺序进行排序。首先在第一个ajax中我们要记录出发顺序,传递到调用的函数中,然后在第二个ajax的回调中调用排序。假设有一个ul,我们把每一个name放在li里面,然后对li进行排序。
//接口路径
var url = "";
var urlGetAddress = "";
//查询关键字
var keyword = "";
var html = "";
$.ajax({
url: url,
data: {
key: keyword,
},
type: "get",
dataType: "json",
success: function(data) {
//这边假设接口给的json格式数据
//有一个数组是result,
//result里面每一个object有一个key是name
$.each(data.result, function(i, el) {
//alert(el.name);
//这边多给一个key用于排序
getAddress(el.name, el.time);
});
},
error: function(data) {
console.log(data);
}
});
function getAddress(name, time) {
Html = "";
$.ajax({
url: urlGetAddress,
data: {
name: name,
},
type: "get",
dataType: "json",
success: function(data) {
//这里是每个name请求一次
//所以不需要遍历
Html +=
'<li id="' + time +'">' + name +
'</li>'
//把li加到ul
$("ul").html(Html);
//调用排序
sortByTime();
},
error: function(data) {
console.log(data);
}
});
}
//按照time排序
function sortByTime() {
var arr = $("ul");
arr.sort(function(a, b){
return $(a).attr("id") < $(b).attr("id") ? 1 : -1;
});//对li进行排序
//清空原来ul的内容添加排序后的内容
$("ul").empty().append(arr);
}
虽然这个方式在结果上是正确的,做到了展现顺序和请求顺序一致,但是还不够简单。如果有A,B,C,D,E五个,在A请求完成后,A的li加入ul,然后对ul进行排序。接着假设是C完成,那么C的li加入ul,然后对ul进行排序。接着是B完成,那么B的li加入ul,然后对ul进行排序……以此类推。那么5个数据就要排序五次,n个数据排序n次。虽然在数据量小的情况下是没什么问题的,但是量大的话感觉还是有哪里不对。(我还是希望能只排一次,但是自己脑子转不过来,没想到= =,有没有大佬提点想法~)
其他想法
还有一种做法就是后端写接口的直接把两个一起给我们就好啦。干嘛要写两个借口呢~
还有看到什么complete回到函数之类的。这个是不管是success还是error都会执行的,相当于try,catch里面的finally。
还有看到用jquery的when什么的。这个我暂时还没用过,好像是jquery为了解决ajax的回调函数的一些内容。下一次等我试一试,再来和大家聊聊~
以上是关于Ajax异步调用的顺序执行的主要内容,如果未能解决你的问题,请参考以下文章