0

我正在使用延迟承诺来中止$http请求(如本文所述)。

但是,我不确定应该如何传播abort()在根级别添加的函数。每次我调用.then()promise 时,都会返回一个新的 promise(没有abort()函数)。

请参阅下面的示例。我有一个控制器调用一个服务,然后调用另一个服务($http发出请求的地方)。该示例不起作用,因为promiseinMyController与返回的 in 不同restService,因此没有称为 的函数abort()

  1. 我如何传播该abort()功能以便它在 中可用MyController
  2. 我可以一直返回原始承诺,然后调用then()它(就像在底部的示例中一样)?电话会发生什么then()?它们是否仍然“同步”调用?

控制器

app.controller("MyController", function($scope, dataService) {
    var promise;

    $scope.loadAndAbortData = function () {
        promise = dataService.getData().then(updateUI);
    };

    $scope.abort = function () {
        if (promise) {
            promise.abort();
        }
    };
}

数据服务

app.service("dataService", function(restService) {
    var service = {
        getData: function () {
            return restService.get().then(function (response) {
                var modifiedData = modifyData(response.data);
                return modifiedData;
            }, function (response) {
                handleError(response.data);
                $q.reject(response.data);
            });               
        };
    };

    return service;
}

休息服务:

app.service("restService", function($http, $q) {
    var service = {
        get: function () {
            var deferredAbort = $q.defer();
            var request = $http.get(url, { timeout: deferredAbort.promise } );

            promise.abort = function () {
                deferredAbort.resolve();
            }

            return promise;
        };
    };

    return service;
}

这是 DataService 和 MyController 的解决方案吗?

app.controller("MyController", function($scope, dataService) {
    var promise;

    $scope.loadAndAbortData = function () {
        promise = dataService.getData();
        promise.then(updateUI);
    };

    $scope.abort = function () {
        if (promise) {
            promise.abort();
        }
    };
}

app.service("dataService", function(restService) {
    var service = {
        getData: function () {
            var promise = restService.get();
            promise.then(function (response) {
                var modifiedData = modifyData(response.data);
                return modifiedData;
            }, function (response) {
                handleError(response.data);
                $q.reject(response.data);
            });

            return promise;           
        };
    };

    return service;
}
4

2 回答 2

1

乔尔,我对此不是 100% 确定,但我会根据您已经尝试过的内容试一试。

整个事情似乎取决于在 RestService 中提供配置映射timeout: Promise中的可解析选项$http(),并以某种方式返回带有 .abort()除标准方法之外的方法的承诺;然后确保该.abort()方法通过DataService“继承”到Controller中。要做到这一点,需要一些小技巧。

我猜你可以这样做:

//RestService:
app.service("restService", function($http, $q) {
    return {
        get: function () {
            var dfrd = $q.defer(),
                promise = $http.get(url, {
                    timeout: dfrd.promise
                });

            //attach the deferred's resolve method as promise's abort method
            promise.abort = dfrd.resolve.bind(dfrd);//(or with an explicit function wrapper, as in the question)

            return promise;
        },
    };
}

同样,在 DataService 中,返回的 Promise 需要一个abort方法,该dfrd.resolve方法又是对 RestService 中方法的引用。

//DataService
app.service("dataService", function(restService) {
    return {
        getData: function () {
            //Here, the natural syntax would be `return restService.get().then(...)`,
            //however a reference to intermediate `restService.get()` is required such that its special `.abort()` method can be attached as the `.abort()` method of the eventually returned promise.
            var promise = restService.get();
            var promise_ = promise.then(function(response) {
                var modifiedData = modifyData(response.data);
                return modifiedData;
            }, function (response) {
                handleError(response.data);
                $q.reject(response.data);
            });
            promise_.abort = promise.abort;//attach promise's abort method as promise_'s abort method.
            return promise_;
        }
    };
});

因此,dataService.getData()应该将带有abort方法的 Promise 传递到 Controller 中。

//Controller
app.controller("MyController", function($scope, dataService) {
    var promise;

    //Here, play the same trick as in the DataService - 
    //ie. assign the intermediate promise rather than the output of the full chain.
    $scope.loadAndAbortData = function () {
        promise = dataService.getData();
        promise.then(updateUI);
    };
    $scope.abort = function () {
        if (promise && promise.abort) {
            promise.abort();
        }
    };
}
于 2014-06-25T16:17:26.123 回答
0

我最终得到了一个解决方案,它“覆盖”了 Promise 的then()函数,以便该函数将遵循所有层,而与 Promise 上调用abort()了多少次无关。then()/catch()/finally()

如果有人找到更好的解决方案或发现此问题的缺陷,我将非常感谢您的意见。

app.service("restService", function($http, $q) {

    function createAbortablePromise(promise, deferredAbort) {
        promise.abort = function () {
            deferredAbort.resolve();
        };

        // A problem with adding the abort function to the promise is that as soon as someone
        // calls then() on this promise (somewhere else in our application), another new promise
        // is returned. This new promise, will not have the abort() function. We can solve this
        // by "overriding" then() recursively.
        var originalThen = promise.then;
        promise.then = function (callback, errback, progressback) {
            // Invoke the original then(). It will return a new promise
            var newPromise = originalThen(callback, errback, progressback);

            // This new promise needs an abort function as well.
            newPromise = createAbortablePromise(newPromise, deferredAbort);

            return newPromise;
        };

        return promise;
    }

    var service = {
        get: function () {
            var deferredAbort = $q.defer();
            var request = $http.get(url, { timeout: deferredAbort.promise } );

            promise.abort = function () {
                deferredAbort.resolve();
            }

            promise = createAbortablePromise(promise, deferredAbort);

            return promise;
        };
    };

    return service;
}
于 2014-07-01T07:41:08.460 回答