我使用 jQuery。而且我不想在我的应用程序上进行并行 AJAX 调用,每个调用都必须等待前一个调用才能开始。如何实施?有帮手吗?
更新如果有任何同步版本的 XMLHttpRequest 或 jQuery.post 我想知道。但是顺序!=同步,我想要一个异步和顺序的解决方案。
我使用 jQuery。而且我不想在我的应用程序上进行并行 AJAX 调用,每个调用都必须等待前一个调用才能开始。如何实施?有帮手吗?
更新如果有任何同步版本的 XMLHttpRequest 或 jQuery.post 我想知道。但是顺序!=同步,我想要一个异步和顺序的解决方案。
有比使用同步 ajax 调用更好的方法来做到这一点。Jquery ajax 返回一个延迟的,因此您可以使用管道链接来确保每个 ajax 调用在下一次运行之前完成。这是一个工作示例,其中包含您可以在 jsfiddle 上玩的更深入的示例。
// How to force async functions to execute sequentially
// by using deferred pipe chaining.
// The master deferred.
var dfd = $.Deferred(), // Master deferred
dfdNext = dfd; // Next deferred in the chain
x = 0, // Loop index
values = [],
// Simulates $.ajax, but with predictable behaviour.
// You only need to understand that higher 'value' param
// will finish earlier.
simulateAjax = function (value) {
var dfdAjax = $.Deferred();
setTimeout(
function () {
dfdAjax.resolve(value);
},
1000 - (value * 100)
);
return dfdAjax.promise();
},
// This would be a user function that makes an ajax request.
// In normal code you'd be using $.ajax instead of simulateAjax.
requestAjax = function (value) {
return simulateAjax(value);
};
// Start the pipe chain. You should be able to do
// this anywhere in the program, even
// at the end,and it should still give the same results.
dfd.resolve();
// Deferred pipe chaining.
// What you want to note here is that an new
// ajax call will not start until the previous
// ajax call is completely finished.
for (x = 1; x <= 4; x++) {
values.push(x);
dfdNext = dfdNext.pipe(function () {
var value = values.shift();
return requestAjax(value).
done(function(response) {
// Process the response here.
});
});
}
有些人评论说他们不知道代码的作用。为了理解它,您首先需要了解 javascript Promise。我很确定 Promise 很快就会成为原生 javascript 语言功能,所以这应该会给你一个很好的学习动力。
你有两个我能想到的选择。一种是通过回调链接它们。另一种是使调用同步而不是异步。
您是否有理由希望它们按顺序排列?这会让事情变慢。
要使调用同步,您需要将 Ajax 调用中的 async 选项设置为 false。请参阅http://docs.jquery.com/Ajax/jQuery.ajax#options上的文档(单击选项选项卡查看它们)。
正如 Nosredna 所说,最好的方法是链接回调。我不建议使用同步 XMLHttpRequest,因为它们会锁定您的整个应用程序。
据我所知,没有太多帮助,但你可以做一些类似于回调 FIFO 的事情。
你可以试试叙述性 javascript http://www.neilmix.com/narrativejs/doc/
不过我自己从来没有用过。如果我想这样做,我会设置某种抽象来链接异步操作。正如其他人所说,ajax 对象的同步版本在等待响应时阻止处理事件。这会导致浏览器在收到响应之前看起来像是被冻结了。
将async选项设置为 false,例如,
$.ajax({ async: false /*, your_other_ajax_options_here */ });
(async () => {
for(f of ['1.json','2.json','3.json']){
var json = await $.getJSON(f);
console.log(json)
};
})()
更多在MDN
看这个:http://docs.jquery.com/Ajax/jQuery.ajax(单击“选项”选项卡)。
但是请记住,同步调用会冻结页面,直到收到响应,所以它不能在生产站点中使用,因为如果出于任何原因他们必须等待 30 秒而浏览器冻结,用户会生气。
编辑:好的,随着您的更新,您想要实现的目标更加清晰;)
因此,您的代码可能如下所示:
$.getJSON("http://example.com/jsoncall", function(data) {
process(data);
$.getJSON("http://example.com/jsoncall2", function (data) {
processAgain(data);
$.getJSON("http://example.com/anotherjsoncall", function(data) {
processAgainAndAgain(data);
});
});
});
这样,只有在收到并处理了对第一个调用的响应时才会发出第二个调用,而只有收到并处理了对第二个调用的响应时才会发出第三个调用。此代码适用于 getJSON,但可以适应 $.ajax。
您可以使用 promise 使 ajax 调用按顺序进行。使用 Array push 和 pop promise 方法,顺序 ajax 调用会容易得多。
var promises = [Promise.resolve()];
function methodThatReturnsAPromise(id) {
return new Promise((resolve, reject) => {
$.ajax({
url: 'https://jsonplaceholder.typicode.com/todos/'+id,
dataType:'json',
success: function(data)
{
console.log("Ajax Request Id"+id);
console.log(data);
resolve();
}
});
});
}
function pushPromise(id)
{
promises.push(promises.pop().then(function(){
return methodThatReturnsAPromise(id)}));
}
pushPromise(1);
pushPromise(3);
pushPromise(2);
同步调用不一定更慢,如果您有一个应用程序,其中 AJAX 调用打开、发布到然后关闭套接字,对套接字的多次调用没有意义,因为某些套接字只能处理单个连接,在这种情况下,排队数据,因此仅在前一个 AJAX 调用完成时才发送,这意味着更高的数据吞吐量。
使用 Node.js 事件怎么样?
var EventEmitter = require('events').EventEmitter;
var eventEmitter = new EventEmitter();
var $ = require('jquery');
var doSomething = function (responseData) {
var nextRequestData = {};
// do something with responseData
return nextRequestData;
};
// ajax requests
var request1 = $.ajax;
var request2 = $.ajax;
var requests = [request1, request2];
eventEmitter.on('next', function (i, requestData) {
requests[i](requestData).then(
function (responseData) {
console.log(i, 'request completed');
if (i+1 < requests.length) {
var nextRequestData = doSomething(responseData);
eventEmitter.emit('next', i+1, nextRequestData);
}
else {
console.log('completed all requests');
}
},
function () {
console.log(i, 'request failed');
}
);
});
var data = {
//data to send with request 1
};
eventEmitter.emit('next', 0, data);
顺序的!=同步的,我想要一个异步和顺序的解决方案
同步执行一般是指“使用相同的时钟”,而顺序执行是指“按顺序执行”。
对于您的特定用例,我认为必须满足这两个条件,因为异步执行意味着可能出现非顺序结果。