我程序中的几乎所有函数都有某种异步调用,但它们都依赖于某些先前函数的结果。因此,我将下一个函数调用硬编码到每个函数中:
function getStuff() {
$.ajax({
...
success: function(results) {
// other functions involving results
getMoreStuff(results);
}
});
}
function getMoreStuff(results) {
$.ajax({
...
success: function(moreResults) {
// other functions involving moreResults
doSomethingWithStuff(moreResults);
}
);
}
等等。它是一个大型链,每个函数调用下一个函数。虽然这在程序中有效,但它使每个函数都无法单独使用。
我对如何避免这个问题有点失落。我无法弄清楚如何使用通用回调函数,因为当我进行函数调用时,它会像这样结束(使用上面的函数):
getStuff(function() {
getMoreStuff(results, doSomethingWithStuff);
};
但是“结果”尚未定义。
解决方案似乎很明显,我只是对它有点密集。遗憾!
答案 0 :(得分:11)
你有几个选择。您可以使用回调函数使用这些函数使用这些函数:
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
的{{1}}来电完成后,调用ajax
并调用 的结果(doSomethingWithStuff
})。
使用getMoreStuff
而非then
非常重要,以便在每个阶段获得正确的结果。 (如果您使用done
,则done
和 getMoreStuff
都会看到doSomethingWithStuff
getStuff
来电的结果。)< / p>
以下是使用ajax
的完整示例:
Fiddle | Alternate Fiddle with the ajax
calls taking one second each(让您更容易看到发生了什么)
ajax
输出:
getStuff starting ajax getMoreStuff got data from first request, starting ajax doSomethingWithStuff got data from second request
您不需要使用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);
}
来获益,您可以使用自己的ajax
和Deferred
对象,这样就可以编写如下链:< / p>
Promise
...适用于您可能有异步完成的任何情况。
这是一个非one().then(two).then(three);
示例:
ajax
输出:
one running one resolving Two: Got 'one' two resolving Three: Got 'two' three resolving
必要时可以组合这两个(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);
}
示例和非 - ajax
示例)。例如,如果我们从ajax
示例中获取getStuff
,我们决定在将数据移交给ajax
之前必须对数据进行一些处理,我们就会更改它:Fiddle
getMoreStuff
请注意我们如何使用它并没有改变:
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);
内。
这是关于整个“承诺”概念的一个伟大的事情(它完全不是jQuery特有的,但是jQuery为我们提供了方便的版本),它非常适合解耦。
答案 1 :(得分:5)
尝试
function getStuff() {
return $.ajax({
...
success: function(results) {
// other functions involving results
}
});
}
function getMoreStuff(results) {
return $.ajax({
...
success: function(moreResults) {
// other functions involving moreResults
}
);
}
然后
getStufff().done(function(){
getMoreStuff().done(doSomethingWithStuff)
})
等
答案 2 :(得分:4)
传递接受参数的回调:
function getStuff( callback ) {
$.ajax({
...
success: function(results) {
// callback with result
callback(results);
}
});
}
function getMoreStuff(results, callback) {
$.ajax({
...
success: function(moreResults) {
// callback with result
callback(moreResults);
}
);
}
function doSomethingWithStuff(results, callback) {
// process results via some means not described herein :)
if (callback){
// callback yet again with results, but only if callback provided this time
callback(stillMoreResults);
}
}
然后使用类似的东西:
getStuff(function(results) {
getMoreStuff(results, function(moreresults){
doSomethingWithStuff(moreresults);
});
};
此模式通常对任何异步操作都有用。它不是特定于Ajax调用(我用它在JQuery中创建一个完整的动画棋盘游戏)。
答案 3 :(得分:2)
解决方案非常简单。您必须使用Publish–subscribe
模式。
使用jQuery进行最简单的实现:
$('body').trigger('joined-game', [game_id, response]);
第一个参数是您要发布的事件名称,第二个参数是数据数组。
最佳做法是在最具体的DOM元素上触发事件,但如果您在多个页面上订阅相同的事件,并且不确定所有页面上是否存在DOM元素,则可以在{{1}上触发它或者一些“转储/合成”不可见的DOM元素总是存在于所有页面上。
body
然后您订阅您想要使用的活动。请记住,除了您的数据,第一个参数始终是事件。
此解决方案的另一个优点是您可以将代码拆分为多个文件。
更多详情:http://webility.pl/en/blog/entry/chaining-javascript-functions-without-dependecy-hell