簡體   English   中英

在使用promises時,如何在Javascript中的異常后重試?

[英]How can you retry after an exception in Javascript when using promises?

我正在使用Bluebird promise庫。 我有一系列有保證的功能,如下所示:

    receiveMessageAsync(params)
    .then(function(data)) {
        return [data, handleMessageAsync(request)];
    })
    .spread(function(data, response) {
        return [response, deleteMessageAsync(request)];
    })
    .spread(function(response, data) {
        return sendResponseAsync(response);
    })
    .then(function(data) {
        return waitForMessage(data);
    })
    .catch (function(err) {
       // handle error here
    });

偶爾sendMessage會失敗,因為,假設要響應的服務器不可用。 我希望代碼能夠繼續嘗試永遠響應,直到成功為止。 你不能簡單地將sendMessage包裝在一個catch中,因為它實際上並沒有拋出異常,我想,它調用了“error”函數,在這個promisified代碼中,它是底部的“catch”。 因此必須有一些方法可以在“catch”部分“重試”發送消息。 問題是,即使我在“catch”中循環重試,我仍然沒有辦法跳到promise鏈並執行剩余的promisified函數。 我該如何處理?

編輯:

我對HTTP帖子的重試最終看起來像這樣:

function retry(func) {
    return func()
        .spread(function(httpResponse) {
            if (httpResponse.statusCode != 200) {
                Log.error("HTTP post returned error status: "+httpResponse.statusCode);
                Sleep.sleep(5);
                return retry(func);
            }
        })
        .catch(function(err) {
            Log.err("Unable to send response via HTTP");
            Sleep.sleep(5);
            return retry(func);
        });
}

這是一個示例重試功能(尚未測試):

function retry(maxRetries, fn) {
  return fn().catch(function(err) { 
    if (maxRetries <= 0) {
      throw err;
    }
    return retry(maxRetries - 1, fn); 
  });
}

我們的想法是,你可以包裝一個函數,該函數返回一個promise,它會捕獲並重試錯誤,直到重試失敗。 所以如果你要重試sendResponseAsync

receiveMessageAsync(params)
.then(function(data)) {
    return [data, handleMessageAsync(request)];
})
.spread(function(data, response) {
    return [response, deleteMessageAsync(request)];
})
.spread(function(response, data) {
    return retry(3, function () { return sendResponseAsync(response); });
})
.then(function(data) {
    return waitForMessage(data);
})
.catch (function(err) {
   // handle error here
});

由於retry承諾實際上不會在所有重試都用完之前拋出,因此您的調用鏈可以繼續。

編輯

當然,如果您願意,您可以永遠循環:

function retryForever(fn) {
  return fn().catch(function(err) { 
    return retryForever(fn); 
  });
}

這是一個小幫手,就像then一樣,但重試了這個功能。

Promise.prototype.retry = function retry(onFulfilled, onRejected, n){
    n = n || 3; // default to 3 retries
    return this.then(function(result) {
         return Promise.try(function(){ 
             return onFulfilled(result); // guard against synchronous errors too
         }).catch(function(err){
             if(n <= 0) throw err;
             return this.retry(onFulfilled, onRejected, n - 1);
         }.bind(this)); // keep `this` value
    }.bind(this), onRejected);
};

哪個可以讓你編寫更漂亮的代碼,如:

receiveMessageAsync(params)
.then(function(data)) {
    return [data, handleMessageAsync(request)];
})
.spread(function(data, response) {
    return [response, deleteMessageAsync(request)];
})
.retry(function(response, data) {
    return sendResponseAsync(response); // will retry this 3 times
})
.then(function(data) {
    return waitForMessage(data);
})
.catch (function(err) {
   // I don't like catch alls :/ Consider using `.error` instead.
});

我剛剛發布了https://github.com/zyklus/promise-repeat ,它會重試一個承諾,直到它超時或達到最大嘗試次數。 它允許你寫:

receiveMessageAsync(params)
...
.spread(retry(
    function(response, data) {
        return sendResponseAsync(response);
    }
))
...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM