【问题标题】:AngularJS Promise best practise for chaining $q.allAngularJS Promise 链接 $q.all 的最佳实践
【发布时间】:2018-05-31 10:46:31
【问题描述】:

我是编写和使用 Promise 的新手,我想要一些建议。我必须链接我的承诺,因为某些功能只能在其他功能之后运行。我确实曾经用很多回调函数来处理这个问题,这看起来非常混乱和混乱。但是随着我正在做的链接......它开始看起来又有点乱了,我想知道我是否正确地这样做......

    function calcNetPriceSaleCharge(theItem) {
    var setInitialChargeAmount = miscSaleSvc.getInitialCharge(theItem);
    var setDiscountAmount = miscSaleSvc.getDiscountAmount(theItem);

    $q
        .all([setInitialChargeAmount, setDiscountAmount])
        .then(function(values) {
            theItem.initialchargeamount = values[0];
            theItem.initialdiscountamount = values[1];
        })
        .then(function() {
            var setActualCharge = miscSaleSvc.getActualCharge(theItem);
            var setVat = miscSaleSvc.setVat(theItem);
            $q
                .all([setActualCharge, setVat])
                .then(function(values) {
                    theItem.actualcharge = values[0];
                    theItem.vat = values[1];
                })
                .then(function() {
                    var setTotal = miscSaleSvc.getSaleTotal(theItem);

                    $q
                        .all([setTotal])
                        .then(function(values) {
                            theItem.total = values[0];
                        })
                        .catch(function(error) {
                            console.log(error);
                        });
                })
                .catch(function(error) {
                    console.log(error);
                });
        })
        .catch(function(error) {
            console.log(error);
        });
}

这确实有效,但我不确定我是否以正确的方式去做!正在调用的示例函数是 this...

srv.getInitialCharge = function(theItem) {
    //set up the deferred var
    var deferred = $q.defer();

    var initialchargeamount = parseFloat(theItem.normalperiodcharge * theItem.quantity);

    if (isNaN(initialchargeamount)) {
        deferred.reject("Error when calculating Initial Charge Amount.");
    } else {
        //set up the failed result
        deferred.resolve(initialchargeamount);
    }

    //return the promise
    return deferred.promise;
};

提前感谢您的帮助:)

【问题讨论】:

  • 更简洁的方式是使用async/await。你也不需要嵌套 Promises。您可以从回调中返回 $q.all() 之类的内容并继续外链。
  • @Sirko async/await 使用未与 AngularJS 框架及其 $q 承诺集成的 ES6 承诺。只有在 AngularJS 执行上下文中应用的操作才能受益于 AngularJS 数据绑定、异常处理、属性监视等。
  • 请记住,您可以使用 $q.reject$q.when 创建拒绝/履行的承诺。不需要使用$q.defer()

标签: javascript angularjs angular-promise ecmascript-5


【解决方案1】:

你创建了一个小回调地狱,这正是 Promises 试图避免的。请记住,您还可以在 then 块中返回一个 Promise,以便在同一调用链中使用 then 进一步处理它:

function calcNetPriceSaleCharge(theItem) {
  var setInitialChargeAmount = miscSaleSvc.getInitialCharge(theItem);
  var setDiscountAmount = miscSaleSvc.getDiscountAmount(theItem);

  $q.all([setInitialChargeAmount, setDiscountAmount])
    .then(function(values) {
      theItem.initialchargeamount = values[0];
      theItem.initialdiscountamount = values[1];
    })
    .then(function() {
      var setActualCharge = miscSaleSvc.getActualCharge(theItem);
      var setVat = miscSaleSvc.setVat(theItem);
      return $q.all([setActualCharge, setVat]);
    })
    .then(function(values) {
      theItem.actualcharge = values[0];
      theItem.vat = values[1];
    })
    .then(function() {
      var setTotal = miscSaleSvc.getSaleTotal(theItem);
      return $q.all([setTotal]);
    })
    .then(function(values) {
      theItem.total = values[0];
    })
    .catch(function(error) {
      console.log(error);
    });
}

另一种变化:

function calcNetPriceSaleCharge(theItem) {
  var setInitialChargeAmount = miscSaleSvc.getInitialCharge(theItem);
  var setDiscountAmount = miscSaleSvc.getDiscountAmount(theItem);

  return $q
    .all([setInitialChargeAmount, setDiscountAmount])
    .then(function(values) {
      theItem.initialchargeamount = values[0];
      theItem.initialdiscountamount = values[1];
    })
    .then(function() {
      var setActualCharge = miscSaleSvc.getActualCharge(theItem);
      var setVat = miscSaleSvc.setVat(theItem);
      return $q.all([setActualCharge, setVat]);
    })
    .then(function(values) {
      theItem.actualcharge = values[0];
      theItem.vat = values[1];
    })
    .then(function() {
      var setTotal = miscSaleSvc.getSaleTotal(theItem);
      return $q.all([setTotal]);
    })
    .then(function(values) {
      return (theItem.total = values[0]);
    });
}

calcNetPriceSaleCharge(something)
  .then(function(finalValue) {
    console.log(finalValue);
  })
  .catch(function(error) {
    console.log(error);
  });

【讨论】:

  • 哦,这看起来好多了!我试试看:)谢谢
  • 非常感谢!效果很好,我的代码又看起来很开心:D
【解决方案2】:

为了完整起见,使用async/await 语法的版本(注意,这可能是not be available for older browsers)。但是,为了更好的可读性,应该更改变量命名。

async function calcNetPriceSaleCharge(theItem) {
  try {
    const setInitialChargeAmount = miscSaleSvc.getInitialCharge(theItem),
          setDiscountAmount = miscSaleSvc.getDiscountAmount(theItem);

    const values0 = await Promise.all( [setInitialChargeAmount, setDiscountAmount] );

    theItem.initialchargeamount = values0[0];
    theItem.initialdiscountamount = values0[1];

    const setActualCharge = miscSaleSvc.getActualCharge(theItem),
          setVat = miscSaleSvc.setVat(theItem);

    const values1 = await Promise.all( [setActualCharge, setVat] );

    theItem.actualcharge = values1[0];
    theItem.vat = values1[1];

    const values2 = await miscSaleSvc.getSaleTotal(theItem);

    theItem.total = values2;

  } catch ( e ) {
    console.log( e );
  }
}

【讨论】:

  • 在编写 ES5 时这可能吗?
  • @Janey 不,不是没有转译器。这就是我关于“旧”浏览器的注释的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-16
  • 2012-03-18
  • 2014-04-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多