角度承诺执行顺序控制

时间:2018-01-15 13:20:49

标签: javascript angularjs

我正在尝试以特定方式使用angularjs异步实现JavaScript函数,如下图所示。

enter image description here

我尝试了几个没有运气的选项http://jsfiddle.net/pb53cafy/4/

示例代码:

function PromiseCtrl($scope, $q, $timeout) {
//
 var Afunction = function() {
        var deferred = $q.defer();
        $timeout(function() {
                deferred.resolve("Success A");
        }, 1000);
        return deferred.promise;
    };

   var Bfunction = function() {
        var deferred = $q.defer();
        $timeout(function() {
                deferred.resolve("Success B");
        }, 2000);
        return deferred.promise;
    };
    $scope.result = "Waiting";
    $q.all([
            Afunction(),
            Bfunction()
        ]).then(function(value) {
        $scope.result = value;       
    }, function(reason) {
        $scope.result = reason;
    });
    //Remaining code ...

}

感谢您对此的帮助

编辑:使用我正在寻找的代码修改http://jsfiddle.net/pb53cafy/11/

4 个答案:

答案 0 :(得分:2)

由于你总是想在A完成时继续,只需等待A,而不是等待B。

你还没有说B是什么,但是:

  1. 如果在A失败的情况下这是一个后备,你将A的失败处理程序链接到B的承诺
  2. 如果它只是你需要的其他东西,那么就用A的结果回报它的承诺;无论如何需要它可以挂钩它
  3. #1的例子:

    var a = Afunction();
    var b = Bfunction();
    a.catch(function() {
        return b; // A failed, chain to B
    }).then(function(value) {
        // ...rest of code...
        $scope.result = value;       
    }, function(reason) {
        $scope.result = reason;
    });
    

    #2的例子:

    var a = Afunction();
    var b = Bfunction();
    a.then(function(value) {
        // ...rest of code...
        // We're at the point we need b
        return b.then(function() {
            // ...possibly more code here...
            $scope.result = value;       
        });
    }, function(reason) {
        $scope.result = reason;
    });
    

    在这两种情况下,我都提到了首先启动A(如果您正在执行类似HTTP请求的事情,这可能很重要)。如果这不重要,您可以摆脱a变量。

答案 1 :(得分:2)

我强烈建议您回答评论中提出的问题。没有这些,很难给你很好的建议。

但是,假设你想要B 的结果,当它在A 之前可用时可以没有它,那么你可以这样做:

$scope.result = "Waiting";
var bResult = null;

var pa = Afunction();
var pb = Bfunction();

pb.then(function (br) {
    bResult = br;
});

pa.then(function (ar) {
    // if B finished first, its value will be in the 
    // bResult closure variable.
    // if A finished first, bResult will be null.

    $scope.result = ar;       
}, function(reason) {
    $scope.result = reason;
});

答案 2 :(得分:2)

您可以创建另一个函数来控制执行过程:

function execute() {
    var deferred = $q.defer();
    var bFinished;

    var aPromise = Afunction().then(function(aRes) {
        if(!bFinished) deferred.resolve(aRes);
        return aRes;
    }).catch(deferred.reject);

    Bfunction().then(function(bRes) {
        bFinished = true;
        return aPromise.then(function(aRes) {
            deferred.resolve(bRes + " and " + aRes);
        });
    });

    return deferred.promise;
}

如果A先完成,它就不会等待B.

如果B先完成,它也会等待A完成。

答案 3 :(得分:1)

我将从ES Promise的角度回答您的问题,但您也可以将其调整为延迟。

解决类似任务的三个基本原语是:

  • Promise.all采用可迭代的承诺并等待所有这些承诺解决或让其中任何一个拒绝。此原语将所有输入承诺视为相等,但这不是您的情况,AB具有不同的含义。但是,请注意它在拒绝案件中是如何运作的。
  • settle allPromise.all的非标准类似物,它等待所有拒绝和解决(与前一个相矛盾)。它还将所有输入承诺视为相等。
  • Promise.race等待首先解决或拒绝。同时将所有输入视为相等。这个与你的情况最相似,请注意它是如何处理拒绝的。

看起来你的案例中的A输入比B更重要,所以我们不能使用任何“对称”原语,我们需要一些手写的原语到resque。 / p>

// first, let's invoke both A and B producers,
// because we need parallel execution
var p_a = AFunction(…)
var p_b = BFunction(…)

// if p_b resolves earlier, we can save it
var shared_b
p_b.then(value => shared_b = value)

// because A is more like a leader, let's wait for it,
// we can't proceed without it in both scenarios,
// we can't use `all` or `race`
var p_pair = p_a.then(value =>
{
    return [ value, shared_b ]
})

p_pair.then(([a, b]) =>
{
    console.log(a, ': A is always here')
    console.log(b, ': B only if was ready fast enough')
})

p_pair现在是Promise<[ A, B | undefined ]>

B拒绝被忽略。

您可以采用简单的方式将其调整为延迟,例如AFunctionBFunction