【问题标题】:Angular: use $q.all for optional promise?Angular:使用 $q.all 作为可选承诺?
【发布时间】:2019-05-12 16:56:48
【问题描述】:

我重构了我的代码,代码更简洁,没有重复。 但我想知道在我的场景中使用 $q.all 是否是最佳选择...

代码逻辑:

  • 我有一个“可选”的承诺。在一种情况下,我需要调用外部 API(= promise),在另一种情况下,我不需要外部调用(= no promise)。
  • 所以我创建了一个变量,我可以在其中存储承诺(或 null 用于没有承诺的场景)。
  • $q.all 等待承诺,然后检查返回值是否是承诺返回的值(场景 1)或 null(场景 2)。

重构前的函数

model.updateWish = function(wish) {
        var defer = $q.defer();

        if (wish.image) {
            // Rename temporary image.public_id to wish_id
            cloudinaryService.renameImage(wish.image.public_id, wish._id,
              function (image) {
                // Update wish with renamed image
                wish.image = image;
                $http.put(URLS.WISH + "/" + wish._id, wish).success(function (wish) {
                    updateWishlist(wish);
                    defer.resolve(wish);
                    console.info("wish updated", wish);
                });
            });
        } else {
            $http.put(URLS.WISH + "/" + wish._id, wish).success(function (wish) {
                updateWishlist(wish);
                defer.resolve(wish);
                console.info("wish updated", wish);
            });
        }
        return defer.promise;
    }

重构后的代码

model.updateWish = function(wish) {
        var defer = $q.defer();

        var renamedImagePromise = null;
        if (wish.image) {
            // Rename temporary image.public_id to wish_id
            renamedImagePromise = cloudinaryService.renameImage(wish.image.public_id, wish._id)
              .then( function (image) {
                // Update wish with renamed image
                wish.image = image;
                return wish;
            });
        }
        // Wait until renameImagePromise is resolved and send updated wish to server
        $q.all([renamedImagePromise]).then(function(wishWithRenamedImage){
            if (wishWithRenamedImage[0]) { // $q.all returns an array, wish is in "wishWithRenamedImage[0]"
                wish = wishWithRenamedImage[0];
            }
            $http.put(URLS.WISH + "/" + wish._id, wish).success(function (wish) {
                updateWishlist(wish);
                defer.resolve(wish);
                console.info("wish updated", wish);
            });
        })
        return defer.promise;
    }

这两个功能都有效,但我想知道这是否是满足我要求的最佳实现...

【问题讨论】:

标签: angularjs angular-promise


【解决方案1】:

使用$q.when,同时避免使用deferred anti-pattern

model.updateWish = function(wish) {
    ̶v̶a̶r̶ ̶d̶e̶f̶e̶r̶ ̶=̶ ̶$̶q̶.̶d̶e̶f̶e̶r̶(̶)̶;̶

    var renamedImagePromise = null;
    if (wish.image) {
        // Rename temporary image.public_id to wish_id
        renamedImagePromise = cloudinaryService.renameImage(wish.image.public_id, wish._id)
          .then( function (image) {
            var wishClone = Object.assign({},wish);
            // Update wish clone with renamed image
            wishClone.image = image;
            return wishClone;
        });
    };
    // Wait until renameImagePromise is resolved and send updated wish to server
    return $q.when(renamedImagePromise).then(function(wishWithRenamedImage){
        var wishToPut = wishWithRenamedImage || wish;
        return $http.put(URLS.WISH + "/" + wish._id, wishToPut)
         .then(function (resolve) {
            var wish = resolve.data;
            updateWishlist(wish);
            ̶d̶e̶f̶e̶r̶.̶r̶e̶s̶o̶l̶v̶e̶(̶w̶i̶s̶h̶)̶;̶
            console.info("wish updated", wish);
            return wish;
        });
    });
    ̶r̶e̶t̶u̶r̶n̶ ̶d̶e̶f̶e̶r̶.̶p̶r̶o̶m̶i̶s̶e̶;̶
};

更新

出于谨慎考虑,我修改了代码以克隆 wish 对象。当对象引用传递给 JavaScript 函数时,该函数可以改变该对象。使用函数式编程最佳实践,应该避免改变对象。

【讨论】:

  • 谢谢,按照您的建议重构了我的代码,一切正常。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-04
  • 2016-02-01
  • 2014-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多