如何使用promise在Javascript中发生exception后重试?

我正在使用蓝鸟承诺库。 我有一系列如下的promisified函数:

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中,因为它实际上并没有抛出一个exception,我想,它调用了“错误”函数,在这个promisified代码中是底部的“catch”。 所以必须有一些方法来在“catch”部分“重试”发送消息。 问题是,即使我在“catch”的循环中重试,我仍然没有办法跳到promise链并执行剩下的promisified函数。 我如何处理这个?

编辑:

我重试了一个HTTPpost,结果如下所示:

 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(尚未testing):

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

这个想法是,你可以包装一个函数,返回一个承诺的东西,将捕获和重试的错误,直到用完重试。 所以,如果你要重试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); }); } 

这是一个小帮手,像那样行事,但重试了这个函数。

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

你可以使用这个promise-retry开源组件,它重试一个返回promise的函数。

例:

 promiseRetry((retry, number) => promiseFunction().catch(retry),{retries:3}) .then((result) => console.log(result)).catch(err => console.log(err)) 

下面是它的工作原理:

 const retry = require('retry'); const isRetryError = (err) => (err && err.code === 'RETRYPROMISE'); const promiseRetry = (fn, options) => { const operation = retry.operation(options); return new Promise( (resolve, reject) => { operation.attempt( (number) => { return fn(err => { if (isRetryError(err)) { err = err.retried; } throw {err:'Retrying', code:'RETRYPROMISE', message: err.message}; }, number) .then(resolve, (err) => { if (isRetryError(err)) { if (operation.retry(err || new Error())) { return; } } reject(err); }); }); }); } 

你也可以使用这个NPM包作为工作。