首页 > 解决方案 > 如何在角度 js 中用 $q 取消承诺

问题描述

我在下面有一个服务。每次打开模型时我都会调用此服务,当我关闭模型然后打开另一个模型时,以前的值会得到反映,在这种情况下,我想在每次关闭模型时取消承诺。

我试过下面的代码,

模型关闭.js

$scope.closeButton = function() {
    DetailDataSvc.storeDefer().resolve()
}

我的服务,(DetailDataSvc)

self.storeDefer = function() {
    return self.deferReturn;
};

self.getDetailReportData = function(postData, functionName) {
    var promises = {};

    var d = $q.defer(),
        metricDataType;
    self.deferReturn = $q.defer();
    promises = {
        detailReport: metricDataType,
        recommendedMetrics: DataSvc.getData(_logPrefix + functionName, recommendedMetricUrl),
        metricInfo: DataSvc.getData(_logPrefix + functionName, metricInfoUrl)
    };
    $q.all(promises).then(function(res) {
        $log.debug(_logPrefix + 'getDetailReportData(). Called from %s. $q.all Response (raw): ', functionName, res);
        else {
            if (response && !_.isEmpty(_.get(response, 'largeCard.chartData.dataValues.rows')) && response.overlayEnabled) {
                self.getMetricOverLay(pdata, functionName).then(function(overlayData) {
                    response.largeCard.chartData.overlay = overlayData;
                    d.resolve(response);
                }, function(msg, code) {
                    d.reject(msg);
                    $log.error(_logPrefix + 'getDetailReportData().   Error code: %s.  Error: ', code, msg);
                });
            } else {
                d.resolve(response);
            }
        }


    }, function(msg, code) {
        d.reject(msg);
        $log.error(_logPrefix + 'getDetailReportData().   Error code: %s.  Error: ', code, msg);
    });

    return d.promise;

};

谁能帮助我我遵循的过程是否正确。

标签: javascriptangularjspromiseangular-promisecancellation

解决方案


您尝试过的事情可能会起作用,但最好通过将返回的承诺$q.all()与可拒绝的 Deferred (即 Deferred,其中引用保留对其拒绝方法)竞争来解决,从而避免延迟的反模式

self.getDetailReportData = function(postData, functionName) {
    var metricDataType = ......; // ???
    var d = $q.defer();

    // cancel previous
    if(self.cancelDetailReport) {
        self.cancelDetailReport(new Error('previous getDetailReportData() cancelled'));
    }
    // keep a reference to the deferred's reject method for next time round.
    self.cancelDetailReport = d.reject;

    var promises = {
        'detailReport': metricDataType,
        'recommendedMetrics': DataSvc.getData(_logPrefix + functionName, recommendedMetricUrl),
        'metricInfo': DataSvc.getData(_logPrefix + functionName, metricInfoUrl)
    };

    // Race aggregated `promises` against `d.promise`, thus providing the required cancellation effect.
    return $q.race([$q.all(promises), d.promise])
    .then(function(response) {
        // arrive here only if all promises resolve and d.reject() has not been called.
        $log.debug(_logPrefix + 'getDetailReportData(). Called from %s. $q.all Response (raw): ', functionName, response);
        if (response && !_.isEmpty(_.get(response, 'largeCard.chartData.dataValues.rows')) && response.overlayEnabled) {
            return self.getMetricOverLay(pdata, functionName)
            .then(function(overlayData) {
                response.largeCard.chartData.overlay = overlayData;
                return response;
            });
        } else {
            return response;
        }
    })
    .catch(function(msg, code) { // signature?
        // all error cases including cancellation end up here.
        var message = _logPrefix + `getDetailReportData().   Error: (${code}): ${msg}`; // or similar
        $log.error(message);
        throw new Error(message); // see https://stackoverflow.com/a/42250798/3478010
    });
};

笔记:

  1. $q.race()对赢得比赛的承诺是透明的,对另一个承诺是不透明的。因此,如果在结算d返回的承诺之前被拒绝,那么将胜出;处理将不会发生,d 的拒绝将落入该条款。或者,如果获胜返回的承诺,那么流程将遵循该承诺的成功路径(即处理)或可能的错误路径(将通过子句)。$q.all()dresponse.catch()$q.all(promises)response.catch()

  2. 不太确定.catch()回调的签名。您通常会期望它接受一个error参数。


推荐阅读