[英]How to chain ajax requests?
I have to interact with a remote api that forces me to chain requests. 我必须与远程api交互,迫使我链接请求。 Thats a callback-hell in asynchronous mode:
这是异步模式下的回调 - 地狱:
// pseudocode: ajax(request_object, callback)
ajax(a, function() {
ajax(b(a.somedata), function() {
ajax(c(b.somedata), function() {
c.finish()
}
})
})
It would be much more readable in sync mode: 它在同步模式下更具可读性:
sjax(a)
sjax(b(a.somedata))
sjax(c(b.somedata))
c.finish()
But Sjax is evil :) How do I do that in a nice not-so-evil and readable way? 但是Sjax是邪恶的:)我该怎么做,在一个
漂亮的不那么邪恶和可读的方式?
You could have a single function which is passed an integer to state what step the request is in, then use a switch statement to figure out what request needs to be make next: 您可以使用一个函数来传递一个整数来说明请求所处的步骤,然后使用switch语句来确定下一个需要进行的请求:
function ajaxQueue(step) {
switch(step) {
case 0: $.ajax({
type: "GET",
url: "/some/service",
complete: function() { ajaxQueue(1); }
}); break;
case 1: $.ajax({
type: "GET",
url: "/some/service",
complete: function() { ajaxQueue(2); }
}); break;
case 2: $.ajax({
type: "GET",
url: "/some/service",
complete: function() { alert('Done!'); }
}); break;
}
}
ajaxQueue(0);
Hope that helps! 希望有所帮助!
Don't use anonymous functions. 不要使用匿名函数。 Give them names.
给他们起名字。 I don't know if you're able to do what I wrote below though:
我不知道你是否能够做我在下面写的内容:
var step_3 = function() {
c.finish();
};
var step_2 = function(c, b) {
ajax(c(b.somedata), step_3);
};
var step_1 = function(b, a) {
ajax(b(a.somedata), step_2);
};
ajax(a, step_1);
This function should chain together a list of ajax requests, if the callbacks always return the parameters necessary for the next request: 如果回调始终返回下一个请求所需的参数,则此函数应将ajax请求列表链接在一起:
function chainajax(params, callbacks) {
var cb = shift(callbacks);
params.complete = function() {
var newparams = cb(arguments);
if (callbacks)
chainajax(newparams, callbacks);
};
$.ajax(params);
};
You can define these callback functions separately and then chain them together: 您可以单独定义这些回调函数,然后将它们链接在一起:
function a(data) {
...
return {type: "GET", url: "/step2.php?foo"}
};
// ...
function d(data) { alert("done!"); };
chainajax({type: "GET", url: "/step1.php"},
[a, b, c, d]);
You could also declare the functions "inline" in the call to chainajax, but that might get a little confusing. 您还可以在调用chainajax时声明函数“inline”,但这可能会让人感到有些困惑。
Maybe what you can do is write a server-side wrapper function. 也许您可以做的是编写服务器端包装函数。 That way your javascript only does a single asynchronous call to your own web server.
这样你的javascript只对你自己的web服务器进行一次异步调用。 Then your web server uses curl (or urllib, etc.) to interact with the remote API.
然后您的Web服务器使用curl(或urllib等)与远程API进行交互。
Update: I've learn a better answer for this if you are using jQuery, see my update under the title: Using jQuery Deffered 更新:如果您使用的是jQuery,我已经为此学到了更好的答案,请参阅标题下的更新:使用jQuery Deffered
Old answer: 老答案:
You can also use Array.reduceRight
(when it's available) to wrap the $.ajax
calls and transform a list like: [resource1, resource2]
into $.ajax({url:resource1,success: function(...) { $ajax({url: resource2...
(a trick that I've learn from Haskell and it's fold/foldRight function). 你也可以使用
Array.reduceRight
(当它可用时)包装$.ajax
调用并将如下列表: [resource1, resource2]
转换为$.ajax({url:resource1,success: function(...) { $ajax({url: resource2...
(我从Haskell学到的一个技巧,它是fold / foldRight函数)。
Here is an example: 这是一个例子:
var withResources = function(resources, callback) {
var responses = [];
var chainedAjaxCalls = resources.reduceRight(function(previousValue, currentValue, index, array) {
return function() {
$.ajax({url: currentValue, success: function(data) {
responses.push(data);
previousValue();
}})
}
}, function() { callback.apply(null, responses); });
chainedAjaxCalls();
};
Then you can use: 然后你可以使用:
withResources(['/api/resource1', '/api/resource2'], function(response1, response2) {
// called only if the ajax call is successful with resource1 and resource2
});
Using jQuery Deffered 使用jQuery Deffered
If you are using jQuery, you can take advantage of jQuery Deffered , by using the jQuery.when()
function: 如果您使用的是jQuery,则可以使用
jQuery.when()
函数来利用jQuery jQuery.when()
:
jQuery.when($.get('/api/one'), $.get('/api/two'))
.done(function(result1, result2) {
/* one and two is done */
});
Check out this FAQ item on the jQuery site. 查看jQuery站点上的此FAQ项。 Specially the callback reference and the complete method.
特别是回调引用和完整方法。
What you want is data from A to be passed to B and B's data passed to C. So you would do a callback on complete. 你想要的是来自A的数据被传递给B和B的数据传递给C.所以你会完成一个回调。
I haven't tried this though. 我没有试过这个。
I believe that implementing a state machine will make the code more readable: 我相信实现状态机会使代码更具可读性:
var state = -1;
var error = false;
$.ajax({success: function() {
state = 0;
stateMachine(); },
error: function() {
error = true;
stateMachine();
}});
function stateMachine() {
if (error) {
// Error handling
return;
}
if (state == 0) {
state = 1;
// Call stateMachine again in an ajax callback
}
else if (state == 1) {
}
}
I made a method using Promises 我使用Promises创建了一个方法
// How to setup a chainable queue method var sequence = Promise.resolve(); function chain(next){ var promise = new Promise(function(resolve){ sequence.then(function(){ next(resolve); }); }); sequence = promise; } // How to use it chain(function(next){ document.write("<p>start getting config.json</p>"); setTimeout(function(){ document.write("<p>Done fetching config.json</p>"); next(); }, 3000); }); chain(function(next){ document.write("<p>start getting init.js</p>") setTimeout(function(){ document.write("<p>starting eval scripting</p>"); next(); }, 3000); }); chain(function(next){ document.write("<p>Everything is done</p>"); });
Bonus : A ultraligth 138 byte limited A- Promise (that can only resolve - without parameters, and only call the last then-method ) 额外奖励 :超级138字节限制A-承诺(只能解析 - 没有参数,只调用最后一个方法)
Background : I made this for node.js at the point where it dose not have promises ATM. 背景 :我为node.js做了这个,它没有承诺ATM。 I didn't want a complete full blown Promise library that I was dependent on and had to include in my package.json, I needed it to be fast and light and do mostly one thing only.
我不想要一个完全成熟的Promise库,我依赖它并且必须包含在我的package.json中,我需要它快速而轻巧,并且只做一件事。 I only needed it for one thing (chaining things like you want to)
我只需要一件事(链接你想要的东西)
function Q(a,b){b=this;a(function(){b.then&&b.then();b.then=i});return b}function i(a){a&&a()}Q.prototype={then:function(a){this.then=a}};
// Start with a resolved object
var promise = new Q(function(a){a()});
// equal to
// var promise = Promise.resolve();
// example usage
new Q(function(resolve){
// do some async stuff that takes time
// setTimeout(resolve, 3000);
}).then(function(){
// its done
// can not return a new Promise
}); // <- can not add more then's (it only register the last one)
// How to setup a chainable queue method with ultraligth promise
var sequence = new Q(function(a){a()});
function chain(next){
var promise = new Q(function(resolve){
sequence.then(function(){
next(resolve);
});
});
sequence = promise;
}
The complete callback is what you're looking for: 您正在寻找完整的回调:
$.ajax({
type: 'post',
url: "www.example.com",
data: {/* Data to be sent to the server. It is converted to a query string, if not already a string. It's appended to the url for GET-requests. */},
success:
function(data) {
/* you can also chain requests here. will be fired if initial request is successful but will be fired before completion. */
},
complete:
function() {
/* For more a more synchronous approach use this callback. Will be fired when first function is completed. */
}
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.