首页 文章

AngularJS中的承诺顺序

提问于
浏览
5

Question:

在AngularJS中是否有"easy"取消( $q - / $http - )承诺或确定承诺解决的顺序?

Example

我有一个长时间运行的计算,我通过 $http 请求结果 . 某些操作或事件要求我在解决初始承诺之前重新开始计算(从而发送新的 $http 请求) . 因此,我想我不能使用像这样的简单实现

$http.post().then(function(){
    //apply data to view
})

因为我无法确保响应按照我发送请求的顺序返回 - 毕竟我想在所有承诺得到妥善解决时显示最新计算的结果 .

但是我想 avoid 等待第一个响应,直到我发送一个这样的新请求:

const timeExpensiveCalculation = function(){
    return $http.post().then(function(response){
        if (isNewCalculationChained) {return timeExpensiveCalculation();}            
        else {return response.data;}
    })
}

Thoughts:

当使用 $http 时,我可以访问响应上的config-object,以使用一些时间戳或其他标识符来手动排序传入的响应 . 但是我希望我能以某种方式告诉角度取消过时的承诺,因此在解决时不会运行.then()函数 .

如果没有 $q -promises的手动实现而不是 $http ,这不起作用 .

也许只是拒绝承诺就是要走的路?但在这两种情况下,它可能需要永远,直到最终在生成下一个请求之前解决了一个promise(在此期间导致一个空视图) .

是否存在一些我缺少的角度API函数,或者是否存在强大的设计模式或带有promise链接的“技巧”或$ q.all来处理返回“相同”数据的多个promise?

4 回答

  • 0

    我通过生成 requestId 来实现,并在promise的 then() 函数中检查响应是否来自最近的 requestId .

    虽然这种方法实际上并没有取消之前的承诺,但它确实提供了一种快速简便的方法来确保您处理最新请求的响应 .

    就像是:

    var activeRequest;
    function doRequest(params){
        // requestId is the id for the request being made in this function call
        var requestId = angular.toJson(params); // I usually md5 hash this
    
        // activeRequest will always be the last requestId sent out
        activeRequest = requestId;
    
        $http.get('/api/something', {data: params})
            .then(function(res){
                if(activeRequest == requestId){
                    // this is the response for last request
    
                    // activeRequest is now handled, so clear it out
                    activeRequest = undefined;
                }
                else {
                    // response from previous request (typically gets ignored)
                }
            });
    }
    

    Edit: 在旁注中,我想补充一点,这个跟踪 requestId's 的概念也可用于防止重复请求 . 例如,在我的 Data service的 load(module, id) 方法中,我做了一个像这样的过程:

    • 根据URL参数生成 requestId .

    • 检入请求哈希表 requestId

    • 如果找不到 requestId :在哈希表中生成新请求和存储承诺

    • 如果找到 requestId :只需从哈希表中返回promise

    • 请求完成后,从哈希表中删除 requestId 的条目 .

  • 0

    取消一个promise只是让它不会在 then 阶段调用 onFulfilledonRejected 函数 . 因此,@ user2263572提到它's always best to let go the promise not cancelled (ES6 native promises can not be cancelled anyways) and handle this condition within it' s then 阶段(如果全局变量设置为2,如下面的代码段所示,忽略任务),我相信你可以找到许多其他方法来做到这一点 . 一个例子可能是;

    很抱歉,对于 reject 函数,我使用 v (看起来像检查字符) resolvex (显而易见) .

    var    prom1 = new Promise((v,x) => setTimeout(v.bind(null,"You shall not read this"),2000)),
           prom2,
    validPromise = 1;
    prom1.then(val => validPromise === 1 && console.log(val));
    // oh what have i done..!?! Now i have to fire a new promise
    prom2 = new Promise((v,x) => setTimeout(v.bind(null,"This is what you will see"),3000));
    validPromise = 2;
    prom2.then(val => validPromise === 2 && console.log(val));
    
  • 4

    我仍然试图找出一种好的单元测试方法,但你可以尝试这种策略:

    var canceller = $q.defer();
    service.sendCalculationRequest = function () {
        canceller.resolve();
        return $http({
            method: 'GET',
            url: '/do-calculation',
            timeout: canceller.promise
        });
    };
    
  • 4

    在ECMA6承诺中,there is a Promise.race(promiseArray) method . 这需要一组promises作为参数,并返回一个promise . 在数组中解析的第一个承诺会将其解析后的值移交给返回的promise的 .then ,而其他数组承诺排在第二个等等,将不会被等待 .

    例:

    var httpCall1 = $http.get('/api/something', {data: params})
        .then(function(val) { 
            return { 
                id: "httpCall1"
                val: val
            }
        })
    var httpCall2 = $http.get('/api/something-else', {data: params})
        .then(function(val) { 
            return { 
                id: "httpCall2"
                val: val
            }
        })
    // Might want to make a reusable function out of the above two, if you use this in Production
    Promise.race([httpCall1, httpCall2])
        .then(function(winningPromise) {
            console.log('And the winner is ' + winningPromise.id);
            doSomethingWith(winningPromise.val);
        });
    

    你可以将它与Promise polyfil一起使用,或者look into the q.race that someone's developed for Angular(虽然我还没有测试过) .

相关问题