简体   繁体   中英

How to cancel a promise with $q in angular js

I have a service below. I will call this service every time when I open a model and when I close the model and then open another one the previous values are getting reflected and in this case I want to cancel the promise every time I close the model.

I have tried the following code,

Model closing.js

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

My Service, (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;

};

Can anyone please help me whether the process I followed is the right one.

What you have attempted could be made to work but it's best fixed by racing the promise returned by $q.all() against a rejectable Deferred (ie. a Deferred, of which a reference is kept to its reject method), thus avoiding the deferred anti-pattern .

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
    });
};

Notes:

  1. $q.race() is transparent to whichever promise wins the race, and opaque to the other. So, if the d is rejected before the promise returned by $q.all() settles, then d will win out; response handling will not happen and d's rejection will fall through to the .catch() clause. Alternatively, if the promise returned by $q.all(promises) wins out then flow will follow that promise's success path (ie response handling) or possibly its error path (which will drop through to the .catch() clause).

  2. Not too sure about the signature of the .catch() callback. You would normally expect it to accept a single error argument.

Assign already created deferred. Try and change this line:

self.deferReturn = $q.defer();

self.deferReturn = d;

只需在要关闭模态时将其隐藏即可。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM