如何在Javascript/jQuery中避免硬编码、链式异步函数?
我的程序中几乎所有的函数都有某种异步调用,但它们都依赖于以前某个函数的结果。因此,我将下一个函数调用硬编码到每个单独的函数调用中:如何在Javascript/jQuery中避免硬编码、链式异步函数?,javascript,jquery,ajax,Javascript,Jquery,Ajax,我的程序中几乎所有的函数都有某种异步调用,但它们都依赖于以前某个函数的结果。因此,我将下一个函数调用硬编码到每个单独的函数调用中: function getStuff() { $.ajax({ ... success: function(results) { // other functions involving results getMoreStuff(results); } })
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);
}
);
}
等等。这是一个大链,每个函数调用下一个函数。虽然这在程序中起作用,但会使每个函数单独失效
我不知道如何避免这个问题。我不知道如何使用常规回调函数,因为当我进行函数调用时,结果是这样的(使用上述函数):
但“结果”还没有定义
解决办法似乎很明显,我只是有点不明白。对不起 试试看
function getStuff() {
return $.ajax({
...
success: function(results) {
// other functions involving results
}
});
}
function getMoreStuff(results) {
return $.ajax({
...
success: function(moreResults) {
// other functions involving moreResults
}
);
}
然后
etc传递接受参数的回调:
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中创建了一个完整的动画棋盘游戏)。概述
你有两个选择。您可以使用这些函数使代码如下所示,使用回调:
getStuff(function(results) {
getMoreStuff(results, doSomethingWithStuff);
});
或者像这样,使用jQuery的延迟
和承诺
对象:
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
也是如此
使用延期
和承诺
jQuery的ajax
功能与它的Deferred
和Promise
功能集成在一起。您只需将return
添加到现有函数中即可,例如:
function getStuff(callback) {
return $.ajax({
...
});
}
(注意:不需要success
回调。)
然后这个代码:
getStuff().then(getMoreStuff).then(doSomethingWithStuff);
这是否:
getStuff
启动其ajax
调用,并返回调用创建的Promise
ajax
调用完成并解析承诺时,将调用getmoretuff
,并将ajax
调用的结果作为其第一个参数。它启动它的ajax
调用getmoretuff
的ajax
调用完成时,将使用该调用的结果调用doSomethingWithStuff
(在getmoretuff
中的一个)然后
,而不是完成
,以便在每个阶段传递正确的结果。(如果使用done
,则getMoreStuff
和doSomethingWithStuff
都将看到getStuff
的ajax
调用的结果。)
下面是一个使用ajax的完整示例:
|(更容易看到发生了什么)
输出:
getStuff starting ajax
getMoreStuff got data from first request, starting ajax
doSomethingWithStuff got data from second request
one running
one resolving
Two: Got 'one'
two resolving
Three: Got 'two'
three resolving
…适用于可能有异步完成的任何情况
下面是一个非ajax示例:
输出:
getStuff starting ajax
getMoreStuff got data from first request, starting ajax
doSomethingWithStuff got data from second request
one running
one resolving
Two: Got 'one'
two resolving
Three: Got 'two'
three resolving
请注意,我们使用它的方式没有改变:
getStuff().then(getMoreStuff).then(doSomethingWithStuff);
所有这些变化都发生在getStuff
中
这是整个“promise”概念的一大优点(这一点对于jQuery来说并不是特别的,但是jQuery提供了方便的版本供我们使用),它对于解耦非常有用。解决方案非常简单。您必须使用
Publish–subscribe
模式。
jQuery最简单的实现:
$('body').trigger('joined-game', [game_id, response]);
第一个参数是要发布的事件名称,第二个参数是数据数组
最好的做法是在最特定的DOM元素上触发事件,但是如果您在多个页面上订阅了相同的事件,并且不确定DOM元素是否在所有页面上都存在,那么您可以在body
上触发它,或者在所有页面上始终存在一些“转储/合成”不可见的DOM元素
$("body").on('joined-game', function(event, game_id, response){
//...
});
然后,您订阅要利用的事件。记住,除了数据之外,第一个参数始终是事件
此解决方案的另一个优点是可以将代码拆分为多个文件
更多详细信息:将回调作为额外参数传递给函数。然后,调用函数可以决定在完成时执行什么操作。您的回调示例只需要返回一个参数。i、 e.
getStuff(函数(结果){getMoreStuff(结果,函数(结果){doSomethingWithStuff(结果);});};
getStuff(函数(结果)…
现在结果被定义了。@Jay:我已经在我的答案中添加了一个完整的ajax示例,使用了Deferred
和Promise
。这到底是如何将所需的结果参数传递给下一个调用的呢?@HiTechMagic在上述两种情况下,参数与ajax响应数据相同。据我所知,没有过程传递给链接函数调用的sed值…如果有任何已处理的结果,则可以接受经典回调参数,或者我们可以创建自己的不同对象。明白了…您链接了Ajax结果。可爱。我假设可能会进行更多的处理(示例中没有)。否则,为什么要麻烦首先传递它:)链不应该从getStuff()转到doSomethingWithStuff()吗一直以来?在我看来,您的示例只执行一个步骤链。最好是按照您的建议执行类似于下面的@HiTech的操作,但只执行延迟。@HiTechMagic是的,将进行更多的处理,然后将处理后的结果输入回调函数。非常抱歉,我在最初的问题中没有指定这一点。不过,我不提这个问题,因此当前的答案是有意义的。这会链接函数,但不会传递异步函数捕获的结果。@Zim84:当传递到的函数返回一个承诺时,下面的函数最终取决于该承诺,而给resolve
的任何参数最终都会运行这适用于ajax
,也适用于您自己的函数。
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);
$('body').trigger('joined-game', [game_id, response]);
$("body").on('joined-game', function(event, game_id, response){
//...
});