将多个回调链接到单个jquery承诺

时间:2015-04-23 19:55:14

标签: javascript jquery promise

我有以下设置,我很好奇这是否是正确的方法。它工作正常,但我只是确保我做得对,或者是否有更好的方法来完成同样的任务。

//custom ajax wrapper
var pageLoadPromise = ajax({
    url: //call to webmethod
});

//this is the way I have been doing it
pageLoadPromise.done(cB1)
    .done(cB2)
    .done(cB3)
    .done(cB4)
    .done(function(){cB5(args);});
    //this function requires that cB1 has been completed

//I tried this and it worked as well
pageLoadPromise.done(cB1,cB2,cB3,cB4)
    .done(function(){cB5(agrs)});

两种方式都可行,但就像我说的那样,我想知道这是否是实现这一目标的正确方法?

更新:

我对我的代码做了一些小调整,特别是针对cB1和回调cB5

pageloadPromise.done(
    function(data){
        cB1(data).done(function(){
            cB5(args);
        });
     },cB2,cB3,cB4
 );

 function cB1(data){
     var cB1Promise = $.Deferred();
     ...

     cB1Promise.resolve();
     return cB1Promise;
 }

3 个答案:

答案 0 :(得分:0)

正如@Bergi所指出的,无论你如何添加回调,它们都按照它们使用done附加的顺序运行。因此,promise.done(cb1, cb2, cb3, cb4).done(cb5)promise.done(cb1).done(cb2).done(cb3).done(cb4).done(cb5)相同。

确保在cb5使用后运行cb1

promise.done( function(data) {cb1(data).done(cb5);}, cb2, cb3, cb4);

如果您不需要,请移除data

我在http://jsbin.com/moqiko/4/edit?js,console,output

中使用了各个场景

答案 1 :(得分:0)

  

双向行动

是的,它们几乎相同(除了.done(function(){cB5});不起作用)。

  

我想知道这是否是正确的方法来实现这一目标?

使用你更喜欢的那个。这是一个设计问题而不是正确性#34;然而,在我看来,这两种方式看起来很奇怪,而且我已经看到了许多承诺代码。我建议使用两种不同的结构,具体取决于您的应用程序的结构:

  • 您使用pageLoadPromise作为初始数据的全局缓存。然后,它可以在不同的地方消耗,可能在不同的时间,用于多种不同的事物(或者甚至可能重复地用于同一事物)。然后在每个模块中重复使用pageLoadPromise

    var pageLoadPromise = ajax({url: …}); // initialisation 
    
    pageLoadPromise.done(cB1); // somewhere
    
    …
    pageLoadPromise.done(cB2); // somewhere else
    
    …
    pageLoadPromise.done(cB3); // other place or time
    
    …
    
  • 您只在一个地方使用pageLoadPromise,并且在加载时基本上只做一件事,除了它是由多个子任务构成的;每个只需要一部分,而不是整个结构。然后只使用一个回调:

    ajax({url: …}).then(function(data) {
        cb1(data.d.cb1data);
        cb2(data.d.cb2data);
        cb3(data.d.cb3data);
        cb4(data.d.cb4data);
        cb5(data.d.cb5data, some_additional_data);
    });
    
  

我对我的代码做了一些小调整,特别是针对cB1和回调cB5

如果cb1没有异步做任何事情,你不应该让它回复。别修改它。如果您想明确表示cb5需要使用cb1的结果执行,那么您应该使用.then进行链接:

var pageLoadPromise = ajax({url: …}); // initialisation 

var cB1promise = pageLoadPromise.then(cB1);

cB1promise.done(cb5); // does get called with the return value of cB1

ajax({url: …}).then(function(data) {
    var res1 = cb1(data.d.cb1data);
    …
    cb5(data.d.cb5data, some_additional_data, res1);
});

答案 2 :(得分:0)

更新。感谢@Bergi指出jQuery的done()实际上返回相同的承诺。我已基于此更新了答案。

如果cB2cB3cB4没有互连,并且所有这些都处理来自ajax调用的相同数据,那么您可以将它们添加到同一个承诺中{{1 }})。

考虑到上述假设,您的第二个代码版本可以简化,而不需要在cB1()中创建新的承诺,也不必再增加一个缩进级别:

pageloadPromise

这里发生的是pageloadPromise.then(cB1).done(cB5); pageloadPromise.done(cB2, cB3, cB4); function cB1(data){ // ... //data2 would be the argument value passed when resolving // your original cB1Promise return data2; } 调用创建了一个新的promise,可以使用.then()返回的任何数据来解析,允许cB1接收该数据而不创建额外的回调并且不涉及另一个承诺(因为我们已经有了一个)。

但是,如果cB5需要另一个cB1,那么ajax的原始实现会更合适(尽管回调计划保持不变)。

最后一点,我没注意到任何失败的处理程序,以防ajax调用失败。