Ответ 1
Обзор
У вас есть несколько вариантов. Вы можете использовать свой код, используя эти функции, с помощью обратных вызовов:
getStuff(function(results) {
getMoreStuff(results, doSomethingWithStuff);
});
или как это, используя объекты jQuery Deferred
и Promise
:
getStuff().then(getMoreStuff).then(doSomethingWithStuff):
Использование обратных вызовов
У обоих getStuff
и getMoreStuff
принять аргумент, который является обратным вызовом для вызова, когда они будут выполнены, например:
function getStuff(callback) {
// ^------------------------------ callback argument
$.ajax({
...
success: function(results) {
// other functions involving results
callback(results);
// ^------------------------------------ use the callback arg
}
});
}
... и аналогично для getMoreStuff
.
Использование Deferred
и Promise
Функция jQuery ajax
интегрируется с ее функциями Deferred
и Promise
. Вы можете просто добавить return
к своим существующим функциям, чтобы выполнить эту работу, например:
function getStuff(callback) {
return $.ajax({
...
});
}
(Примечание: нет необходимости в обратном вызове success
.)
Затем этот код:
getStuff().then(getMoreStuff).then(doSomethingWithStuff);
делает следующее:
-
getStuff
запускает вызовajax
и возвращаетPromise
, который вызывает вызов. -
Когда вызов
ajax
завершает и разрешает обещание, в качестве первого аргумента вызываетсяgetMoreStuff
с результатами вызоваajax
. Он начинает свой вызовajax
. -
Когда вызов
getMoreStuff
ajax
завершается,doSomethingWithStuff
вызывается с результатами этого вызова (тот, что находится вgetMoreStuff
).
Важно использовать then
, а не done
, чтобы получить правильные результаты, переданные на каждом этапе. (Если вы используете done
, то как getMoreStuff
, так и doSomethingWithStuff
будут отображаться результаты вызова getStuff
ajax
.)
Здесь приведен полный пример с использованием ajax
:
Fiddle | Alternate Fiddle с вызовами ajax
, занимающих одну секунду каждый (упрощает просмотр того, что происходит)
function getStuff() {
display("getStuff starting ajax")
return $.ajax({
url: "/echo/json/",
type: "POST",
data: {json: '{"message": "data from first request"}'},
dataType: "json"
});
}
function getMoreStuff(results) {
display("getMoreStuff got " + results.message + ", starting ajax");
return $.ajax({
url: "/echo/json/",
type: "POST",
data: {json: '{"message": "data from second request"}'},
dataType: "json"
});
}
function doSomethingWithStuff(results) {
display("doSomethingWithStuff got " + results.message);
}
getStuff().then(getMoreStuff).then(doSomethingWithStuff);
function display(msg) {
var p = document.createElement('p');
p.innerHTML = String(msg);
document.body.appendChild(p);
}
Вывод:
getStuff starting ajax getMoreStuff got data from first request, starting ajax doSomethingWithStuff got data from second request
Вам не нужно использовать ajax
, чтобы получить выгоду от этого, вы можете использовать свои собственные объекты Deferred
и Promise
, которые позволяют писать такие цепочки:
one().then(two).then(three);
... для любой ситуации, когда у вас могут быть асинхронные доработки.
Здесь пример не ajax
:
function one() {
var d = new $.Deferred();
display("one running");
setTimeout(function() {
display("one resolving");
d.resolve("one");
}, 1000);
return d.promise();
}
function two(arg) {
var d = new $.Deferred();
display("Two: Got '" + arg + "'");
setTimeout(function() {
display("two resolving");
d.resolve("two");
}, 500);
return d.promise();
}
function three(arg) {
var d = new $.Deferred();
display("Three: Got '" + arg + "'");
setTimeout(function() {
display("three resolving");
d.resolve("three");
}, 500);
return d.promise();
}
one().then(two).then(three);
function display(msg) {
var p = document.createElement('p');
p.innerHTML = String(msg);
document.body.appendChild(p);
}
Вывод:
one running one resolving Two: Got 'one' two resolving Three: Got 'two' three resolving
Эти два (пример ajax
и пример не ajax
) могут быть объединены при необходимости. Например, если мы возьмем getStuff
из примера ajax
, и мы решили, что нам нужно выполнить некоторую обработку данных, прежде чем передать его на getMoreStuff
, мы бы изменили его следующим образом: Fiddle
function getStuff() {
// Create our own Deferred
var d = new $.Deferred();
display("getStuff starting ajax")
$.ajax({
url: "/echo/json/",
type: "POST",
data: {json: '{"message": "data from first request"}', delay: 1},
dataType: "json",
success: function(data) {
// Modify the data
data.message = "MODIFIED " + data.message;
// Resolve with the modified data
d.resolve(data);
}
});
return d;
}
Обратите внимание, что мы не используем это:
getStuff().then(getMoreStuff).then(doSomethingWithStuff);
Все, что изменилось, находилось в пределах getStuff
.
Это одна из величайших вещей по всей концепции "обещания" (которая совсем не специфична для jQuery, но jQuery дает нам удобные версии), это фантастика для развязывания вещей.