Как связать запросы ajax?
Мне нужно взаимодействовать с удаленным api, что заставляет меня запросить цепочку. Thats callback-hell в асинхронном режиме:
// pseudocode: ajax(request_object, callback)
ajax(a, function() {
ajax(b(a.somedata), function() {
ajax(c(b.somedata), function() {
c.finish()
}
})
})
Это было бы гораздо более читаемым в режиме синхронизации:
sjax(a)
sjax(b(a.somedata))
sjax(c(b.somedata))
c.finish()
Но Sjax злой:) Как это сделать в nice не-злом и читаемом?
Ответы
Ответ 1
Не используйте анонимные функции. Дайте им имена. Я не знаю, можете ли вы сделать то, что я написал ниже, хотя:
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);
Ответ 2
У вас может быть одна функция, которой передается целое число, чтобы указать, на каком этапе находится запрос, а затем используйте оператор 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);
Надеюсь, что это поможет!
Ответ 3
Эта функция должна объединить список запросов ajax, если обратные вызовы всегда возвращают параметры, необходимые для следующего запроса:
function chainajax(params, callbacks) {
var cb = shift(callbacks);
params.complete = function() {
var newparams = cb(arguments);
if (callbacks)
chainajax(newparams, callbacks);
};
$.ajax(params);
};
Вы можете определить эти функции обратного вызова отдельно, а затем соединить их вместе:
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]);
Вы также можете объявить функции "inline" в вызове chainajax, но это может немного запутать.
Ответ 4
Возможно, что вы можете сделать, это написать серверную функцию обертки. Таким образом, ваш javascript выполняет только один асинхронный вызов на ваш собственный веб-сервер. Затем ваш веб-сервер использует завиток (или urllib и т.д.) Для взаимодействия с удаленным API.
Ответ 5
Обновление: я узнал для этого лучший ответ, если вы используете jQuery, см. мое обновление под заголовком: Использование jQuery Deffered
Старый ответ:
Вы также можете использовать Array.reduceRight
(когда он доступен), чтобы обернуть вызовы $.ajax
и преобразовать список, например: [resource1, resource2]
в $.ajax({url:resource1,success: function(...) { $ajax({url: resource2...
(трюк, который я изучил из Haskell, и его fold/foldRight функция).
Вот пример:
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();
};
Затем вы можете использовать:
withResources(['/api/resource1', '/api/resource2'], function(response1, response2) {
// called only if the ajax call is successful with resource1 and resource2
});
Использование jQuery Deffered
Если вы используете jQuery, вы можете использовать jQuery Deffered, используя функцию jQuery.when()
:
jQuery.when($.get('/api/one'), $.get('/api/two'))
.done(function(result1, result2) {
/* one and two is done */
});
Ответ 6
Посмотрите этот пункт часто задаваемых вопросов на сайте jQuery. Специально ссылка обратного вызова и полный метод.
То, что вы хотите, это данные из A, которые должны быть переданы B и B, переданным C. Таким образом, вы выполнили бы обратный вызов при завершении.
Я не пробовал это, хотя.
Ответ 7
Я считаю, что реализация конечного автомата сделает код более читаемым:
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) {
}
}
Ответ 8
Я сделал метод, используя 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>");
});
Ответ 9
Полный обратный вызов - это то, что вы ищете:
$.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 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. */
}
});