【问题标题】:API design: How can I combine result of two deferred jQuery objects?API 设计:如何组合两个延迟的 jQuery 对象的结果?
【发布时间】:2016-04-02 16:21:16
【问题描述】:

假设我能够独立获取 ($.ajax)、处理 (process_*) 和保存 (store_* =) 数据 AB 并且已经拥有 API:

var store_A;
function A() {
  $.ajax({url: "/getA"}).done(function(data) {
     store_A = process_A(data);
}); }

var store_B;
function B() {
  $.ajax({url: "/getB"}).done(function(data) {
     store_B = process_B(data);
}); }

我有一个函数 C() 能够将 store_Astore_B 组合成一些东西:

var store_C;
function C() {
   store_C = process_C(store_A, store_B);
}

假设A()B()C() 是公共API,而所有其他东西都是内部的,实际上是复杂的代码(例如,我不能同时链接$.ajax)。

我想使用jQuery Deferred API 将上面的代码重构为新的 API,以便我可以请求任何情况:

case1: after(A).do(C)
case1: after(B).do(C)
case2: afterParallelJobsFinished(A, B).do(C)

并确保 store_Astore_B 按要求更新,store_C 仅在 A/B 之一或两者按要求更新后更新。


想象我们有 web 应用程序,用户可以在其中管理一组收入和支出。

在页面加载时,我们从不同的数据源(即$.ajax并行获得收入和支出,渲染视图和存储数据(通常是混合在一起的process_* / store_* = ) 并显示total = SUM(incomes) - SUM(expenses)所有数据到达时

那是case2

当用户在case1 中编辑费用并请求部分页面更新时,因为我们只需要加载/渲染/存储扩展即可获得正确的total = SUM(incomes) - SUM(expenses)

【问题讨论】:

  • 你可以使用$.when,但是你需要在store_X中存储promise。
  • 来自两个独立的$.ajax() 我得到了两个承诺。我怎样才能将它们结合起来?我想保留独立运行 A()B()C() 的能力。

标签: javascript jquery ajax promise jquery-deferred


【解决方案1】:

$.when() 可以接受任意数量的延迟对象。 It can even take a dynamic number 如果你不知道你会打多少电话。

$.when(callA(), callB()).done(function() {
 // Do stuff here when both calls are done
});

function callA() {
  return $.ajax({
    url: ...,
    success: function() {
      // Do stuff here when callA is done
    }
  });
}

function callB() {
  return $.ajax({
    url: ...,
    success: function() {
      // Do stuff here when callB is done
    }
  });
}

【讨论】:

  • 不错!我可以使用 return $.ajax().done(...) 语法而不是 return $.ajax({success: ...}) 吗?它们是等价的吗?
  • 不,不一样。您不希望在其中一个完成时调用done - 只有当它们全部完成时。
  • 谢谢。我认为我的问题主要是因为 donesuccess 的误解。
  • 非常正确。文档根本没有说明它们如何协同工作。在某些情况下,您可以使用done 代替success,但对于上述用例,我建议在我展示的位置同时使用。
  • 我不会使用done,而是then。这样它仍然会返回一个承诺。像这样:return $.ajax().then(...)。当 callA 和 callB 中的每个 then 函数完成时,$.when() 将被执行。我个人认为将$.Deferred 逻辑与成功回调混合起来有点难看。 “先发生什么?实际返回什么?他们都通过了结果吗?成功链了吗?”坚持$.Deferred 可以避免的所有有效问题
【解决方案2】:

现在当我熟悉jQuery.Deffered API 后,我想添加更多自我表达的示例:

function callA() {
  return $.ajax({ url: ... })
    .done(function(data) { successA(data); })
    .fail(function(data) { failA(data); });
}

function callB() {
  var promise1 = $.ajax({ url: ... })
    .done(function(data) { succB_1(data); })
    .fail(function(data) { failB_1(data); });
  var promise2 = $.ajax({ url: ... })
    .done(function(data) { succB_2(data); })
    .fail(function(data) { failB_2(data); });
  return $.when(promise1, promise2)
    .done(function(data1, data2) { succCombined(data1, data2); })
    .fail(function(data1, data2) { failCombined(data1, data2); });
}

$.when(callA(), callB()).done(function() {
 // Do stuff here when both calls are done
});

注意在callA/callB里面我使用data/data1/data2,因为我知道内部API协议。在最后几行中,我不希望 callA/callB 返回一些合理的东西。但是如果我将公共 API 添加到 callA/callB 我可以使用:

$.when(callA(), callB()).done(function(resultA, resultB) {
 // Do stuff here when both calls are done
});

【讨论】:

    【解决方案3】:

    这是 Matthew Herbst 的答案的修订版,仅坚持 Promise 逻辑。这避免了混合 Promise 逻辑和 ajax success: 回调造成的不必要的混淆。

    $.when(callA(), callB()).done(function() {
        // Do stuff here when both .then()'s are complete
    });
    
    function callA() {
        return $.ajax({
            url: ...,
        }).then(function(result){
            // Do something when callA finishes
            return result;
        });
    }
    
    function callB() {
        return $.ajax({
            url: ...,
        }).then(function(result){
            // Do something when callB finishes
            return result;
        });
    }
    

    【讨论】:

      猜你喜欢
      • 2010-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多