你如何在Angular的$ timeout中包装一个promise链?

时间:2016-04-19 13:42:33

标签: javascript angularjs timeout promise

我有一个获取报告的服务:

ReportsResource.getActiveUsers()。这使用$http然后返回一个promise。

然后我就这样使用它:

var request = ReportsResource.getActiveUsers();

request.then(populateActiveUsersTable, handleError);

但是,问题是,在后端获取活动用户报告的请求可能需要几秒钟到30多分钟。

  • 如果您发出请求并且没有可用的缓存报告,它会生成报告,然后请求会等待该请求的数据(同样,可能是2秒或30分钟)。

    < / LI>
  • 如果您发出请求并且当前正在生成报告,则会立即返回响应,告知您报告尚未就绪。此时,您可以继续轮询以查看报告是否已准备就绪。

  • 如果报告已准备好(缓存),则会立即返回报告数据的响应。

我需要的是将请求包装在等待最多10秒的超时中,然后在响应时间超过10秒后中止,并开始轮询服务器以询问报告是否已准备就绪。但是如果请求在10秒内解决,它应该取消超时并正常执行promise链。

不确定如何处理这个。

2 个答案:

答案 0 :(得分:0)

根据情况,我认为最好使用WebSocket而不是timeout功能。使用WebSocket,您只需要注册每次从服务器发送更新/更改时运行所需的功能。 websocket不需要保持轮询,而是需要更少的资源和更高的效率。但它需要在后端做一些工作。

实现延迟了不同的后端语言。您可能需要与后端人员(或您自己)交谈。希望这可以给你一些想法。

===编辑===

如果您想使用timeoutinterval等服务,请使用以下代码:

//inside your controller
var pollingPromise = $q.defer(); //used to controll the fired $http request

var pollingActiveUsers = function() {

    ReportsResource.getActiveUsers(pollingPromise).then( function(data){
        //stop polling
        $interval.cancel(pollingProcess);
        //set to the controller's scope
        $scope.activeUsers = data;
        //populate the activeUsersTable
        populateActiveUsersTable();
    });
};

//init the first request
pollingActiveUsers();

//polling for every 10secs
var pollingProcess = $interval( function() {
    //resolve the previous polling request which mean cancel the previous $http request if it waits longer than 10 secs
    pollingPromise.resolve();

    //start another polling, a new pollingPromise is required
    pollingPromise = $q.defer();

    pollingActiveUsers();
}, 10000);

//In your service ReportsResource
//you have to make another change function getActiveUsers() to make this work, you have to pass the pollingPromise to the $http method, so you can cancel the $http request:
var function getActiveUsers = function(promiseObj) {
    return $http.get('someUrl', { timeout: promiseObj });
};

很少有人担心:

  1. 已经解雇的$ http请求应该被取消/解决,如果它需要超过10秒。所以pollingPromise是我们需要的。更多信息:cancel unresolved promise
  2. 应每10秒触发一次新的$ http请求,$interval解决此问题,$interval.cancel()函数将停止此间隔。
  3. 轮询应在收到所需数据后立即停止
  4. 在您的应用中应用时,可能需要更改代码。

答案 1 :(得分:0)

$q {{3}}与$timeout一起使用。使用$q.defer()创建延迟,使用超时创建请求,并在then处理程序中转发结果以解决延迟。如果请求超时,则开始轮询。立即退还延期的承诺。

var d = $q.defer() // defered for the final result

function poll() {
    $http({...}).then( //poll request 
        function(res) {
            if (ready(res))
                d.resolve(res)
            else {
                $timeout(poll, 10000)
            }
        },
        function(err) {
            d.reject(err)
        })
}

$http({ timeout: 10000, ... }).then(
    function(res) {
        d.resolve(res)
    }, // return result directly
    function(err) { // error or timeout
        if (realError(err)) // check if real error 
            d.reject(err)
        else { //timeout
            $timeout(poll, 10000)
        }
    })
return d.promise

您可以重复使用返回的promise,经常调用then来等待或获取缓存的结果。