【问题标题】:Deferred Promise - Run Functions One by One after each completesDeferred Promise - 每次完成后一个接一个地运行函数
【发布时间】:2017-05-04 22:05:24
【问题描述】:

我有 3 个对后端系统进行异步调用的函数:fnOne、fnTwo、fnThree。我知道我做得不对,但无法找出正确的方法。

我开始尝试在每个完成后一个接一个地调用它们:

但是,fnOne 内部已经有一个延迟对象,当它解决时,它正在解决我的承诺。

$.when(oController._fnOne()).done(function(){
    console.log("fn one complete");
});

功能

_fnOne: function(){

    var oController = this;

 //when the deferred is done in _checkInstanceStatus, it is resolving the above, rather than the pDeferred in this function resolving the above.
$.when(oController._checkInstanceStatus(oParams)).done(function(oStatusData) {
        //does some stuff 
        return $.Deferred(function() {
            var pDeferred = this;
            //does a call for data and upon success i will resolve ..
            pDeferred.resolve();
        });
    });
}

其他功能

_checkInstanceStatus: function(oParams){
            return $.Deferred(function() {
                var pDeffered = this;
                //does a call for data and upon success i will resolve...
                pDeffered.resolve(data);

                });
            });
        },

然后计划是尝试将它们链接起来,让它们一个接一个地运行,如下所示:

$.when(oController._fnOne())
.then(oController._fnTwo())
.then(oController._fnThree())
.done(function(){
    console.log("all complete!");
});

【问题讨论】:

  • 恐怕问题中没有足够的信息来给你一个可靠的答案。例如,fnOne 所做的“打电话”是什么?它是返回 Promise 还是 Deferred 的东西?
  • @T.J.Crowder 感谢您的回复,是否在调用后端系统获取数据的地方进行了调用,在调用成功完成 pDeferred.resolve() 后,我正在解决延迟问题;
  • 调用后端系统是通过什么$.ajax?再说一遍:它是返回 Promise 还是 Deferred,还是...?
  • 它既不返回 Promise 也不返回 Deferred。这是使用其 JavaScript API 调用 Amazon Web Services - 例如,ec2.describeInstanceStatus(params, function(err, data) {... 这将返回服务器的当前状态

标签: javascript jquery promise deferred


【解决方案1】:

有几点:

  1. 如果您要传递一个 Deferred,则无需使用 $.when

  2. fnOne(可能还有其他人)需要返回一个 promise/Deferred,以便您知道它何时完成。由于它使用的是_checkInstanceStatus,它返回一个Deferred,它可以通过使用then来做到这一点:

所以fnOne 可能看起来像这样:

fnOne: function() {
    var oController = this;
    return oController.__checkInstanceStatus(oParams).then(function(oStatusData) {
        var pDeferred = $.Deferred();
        callAmazon(function() {
            if (/*successful*/) {
                pDeferred.resolve();
            } else {
                pDeferred.reject();
            }
        });
        return pDeferred.promise(); // Or just the Deferred if you like, but
                                    // normally you want to share promises, not
                                    // Deferred objects
    });
}

注意它是如何返回调用then 的结果,这是通过调用then 创建的承诺。该承诺将根据您从 then 处理程序返回的承诺来解决。

您将遵循与其他功能相同的模式。

要将它们一个接一个地链接起来,您可以这样做:

oController._fnOne()
.then(oController._fnTwo)        // Notice no () on that, we're passing the
.then(oController._fnThree)      // function in, not calling it. Same on this line.
.then(function() {
    console.log("all complete!");
})
.catch(function(error) {
    // Do something about the error
});

(我假设 _fnOnefnOne 是相同的功能。)

我假设一个相对较新的 jQuery 版本在 Deferreds 中具有 Promises 支持。


旁注:我会切换到使用本机 Promises(如果需要支持旧浏览器,则使用 polyfill)而不是使用 jQuery 的 Deferred,它有......嗯,它有很多历史,API 有变得很麻烦。 :-)

使用原生承诺:

fnOne: function() {
    var oController = this;
    return oController.__checkInstanceStatus(oParams).then(function(oStatusData) {
        return new Promise(function(resolve, reject) {
            callAmazon(function() {
                if (/*successful*/) {
                    resolve();
                } else {
                    reject();
                }
            });
        });
    });
}

用法是一样的(因为我使用了第一个示例中已经添加到 Deferred 的 Promise API)。

【讨论】:

  • Appologies,我在尝试简化代码时也有一些错字!非常感谢,这个很好用!!我也改用原生 promises
  • 最后一个问题 - 我如何将数据从一个函数依次传递到下一个函数?
  • @neeko:您可以将其作为参数传递给resolve,然后在目标函数中将其作为参数接收。例如,如果_fnOne 执行resolve("foo"),则_fnTwo 上方的链将具有"foo" 的值。 :-)
  • 啊有道理!另外,_fnTwo 中的第二个函数.then(oController._fnTwo)this 现在是 promise 而不是控制器,我是否必须将控制器也传递给 fnTwo 才能使用它?
  • @neeko:你可以使用bind.then(oController._fnTwo.bind(oController))。或者使用包装函数:.then(function(value) { return oController._fnTwo(value))(箭头版本更简洁:.then(value => oController._fnTwo(value)),支持很好,但还不通用)。
【解决方案2】:

很难理解你的功能。所以我用 3 种不同的方式定义了 3 个新的 func 变得很简单,这样你就可以更容易地理解 jquery deferred。

var funcOne = function() {
  var defer = $.Deferred();
  $.ajax('/echo/json')
    .then(function(data) {
      console.log('func1', data);
      return defer.resolve(data);
    });
  return defer;
}

var funcTwo = function() {
  console.log('begin call func 2');
  return $.ajax('/echo/json')
    .then(function(data) {
      console.log('func2', data);
      return $.Deferred().resolve(data);
    });
}

var funcThree = $.ajax('/echo/json');

funcOne()
  .then(funcTwo)
  .then(funcThree)
  .then(function(data) {
    console.log('finally got func 3 data', data)
  });

jsfiddle 链接:https://jsfiddle.net/zmjLaznn/

【讨论】:

    猜你喜欢
    • 2011-12-04
    • 1970-01-01
    • 2014-09-28
    • 2011-05-14
    • 1970-01-01
    • 2017-03-18
    • 1970-01-01
    • 2022-11-17
    • 1970-01-01
    相关资源
    最近更新 更多