函数抽象&promise函数作为参数

Function abstraction & promise function as a parameter

我正在尝试抽象下面的函数,以便我可以轻松地重用。函数基本上运行一个给定的函数,该函数 returns 承诺最多 5 次或直到承诺得到解决。 DataFn 让我特别难过。它 returns 一个承诺,但是当运行函数在第一次失败后第二次执行时,它不会再次尝试连接到服务器。如果我对函数名称进行硬编码,它会起作用,但作为传递的参数仅在开始时起作用。

var persistentPromise = (function() {
    var maxRetries = 0;
    return function run(dataFn, messageObject) {
        var deferred = $q.defer();
        dataFn.$promise.then(function (response) {
                deferred.resolve(response);
            },
            function (response) {
                if(response == 503) {
                    if(++maxRetries < 6) {
                        messageService.emit(messageObject.warning);
                        $timeout(function () {
                            run(dataFn, messageObject);
                        }, 10000);
                    } else {
                        messageService.emit(messageObject.end);
                        deferred.reject(messageObject.na);
                    }
                }
            });
        deferred.promise.then(function (response) {
            $scope.transactionData = {
                transactions: kpiService.totalArrayAmountWithRange(response.rows, 2, 0, response.rows.length / 2) + kpiService.totalArrayAmountWithRange(response.rows, 2, response.rows.length / 2 + 1, response.rows.length)
            };
            usSpinnerService.stop('loaderspin');
        }, function(response) {
            usSpinnerService.stop('loaderspin');
            $scope.transactionData = {
                transactions: response.na.msg
            };
        });
    };
})();

/* calling the function */
persistentPromise(promiseFunction, someMessageObject);

您可以将该代码完全分解为可重用的部分。请记住,承诺使用 return 语句并抽象出异步值的基础。

Promises 表示值而不是操作 - 您的 dataFn 不是函数,而是函数的结果,您只是等待 n 10 秒,然后实际上不再执行任何调用。

让我们从 retry:

开始
// fn - arbitrary function that returns a promise, in your case this is what
// generates dataFn and __not__ dataFn itself. n - the number of retries
function retry(fn, n){ 
    var reasons = []; // to keep rejection reasons
    return $q.when().then(function retry(){ // start the chain
        return fn(). // call the function
               catch(function(err){ // if it failed
                   reasons.push(err); // accumulate reasons for failure of fn()
                   if(n-- <= 0) return $q.reject(reasons); // no more retries
                   return retry(); // recursive call, note the return
               });
    });
}

现在您可以多次重试任何 promise 返回函数,这是一个可分解的位。

现在让我们再次查看您的代码。通过在函数中包含 $scope 和 uiSpinner 可以完成很多工作。让我们看看那个微调器。

function spinUntil(fn){
    uiSpinnerService.start("loaderspin"); // start spinning, here and not outside
    return fn().finally(function(){ // after FN resolves
        uiSpinnerService.stop("loaderspin");
    });
}

这会让您的整个代码看起来像:

spinUntil(function(){
    return retry(promiseReturningFunction, 5);
}).then(function(data){ // retries performed, spinner done
    $scope.transactionData = data; // assign here, don't complect the scope and the fn.
    // spinner and retries already done, $scope is not a concern of retry or spinUntil
});

我附带了这个函数,即使函数 returns 是一个承诺,它也能很好地工作。 Return 也是一个承诺,因此可以轻松处理结果。

function (fn, params, n) {
        var deferred = $q.defer();
        (function retry() {
            return fn(params).$promise
                .then(function (response) {
                    deferred.resolve(response);
                },
                function (response) {
                    if (n <= 0) {
                        deferred.reject(response);
                        return;
                    }
                    n--;
                    $timeout(function () {
                        return retry();
                    }, 5000);
                });
        })();
        return deferred.promise;
    };