NodeJS超时如果未能及时完成Promise

如何在一定的时间后超时? 我知道Q有一个承诺超时,但我使用本机NodeJS承诺,他们没有.timeoutfunction。

我错过了一个还是它的包装不同?

或者,下面的执行是否在不吸取内存,实际上按预期工作?

我也可以使它以某种方式包裹在全球范围内,所以我可以使用它创build的每一个承诺,而不必重复setTimeout和clearTimeout代码?

function run() { logger.info('DoNothingController working on process id {0}...'.format(process.pid)); myPromise(4000) .then(function() { logger.info('Successful!'); }) .catch(function(error) { logger.error('Failed! ' + error); }); } function myPromise(ms) { return new Promise(function(resolve, reject) { var hasValueReturned; var promiseTimeout = setTimeout(function() { if (!hasValueReturned) { reject('Promise timed out after ' + ms + ' ms'); } }, ms); // Do something, for example for testing purposes setTimeout(function() { resolve(); clearTimeout(promiseTimeout); }, ms - 2000); }); } 

谢谢!

本机JavaScript承诺没有任何超时机制。

关于你的实现的问题可能会更适合http://codereview.stackexchange.com ,但是有一些注意事项:

  1. 你并没有提供一个实际上在承诺中做任何事情的方法

  2. setTimeoutcallback中不需要clearTimeout ,因为setTimeout安排一次性定时器。

  3. 由于承诺一旦解决/拒绝就无法解决/拒绝,您不需要检查。

所以也许有这样的一些东西:

 function myPromise(ms, callback) { return new Promise(function(resolve, reject) { // Set up the real work callback(resolve, reject); // Set up the timeout setTimeout(function() { reject('Promise timed out after ' + ms + ' ms'); }, ms); }); } 

像这样使用:

 myPromise(2000, function(resolve, reject) { // Real work is here }); 

(或者你可能希望它更复杂一点,请参阅下面的更新。)

我会稍微担心这个事实,语义稍有不同(没有new ,而你用newPromise构造函数),所以你可以调整。

另一个问题当然就是大多数时候,你不想构造新的承诺,所以不能使用上面的。 大多数情况下,你已经有了一个承诺(之前的调用结果等)。 但是对于你真正构build新的承诺的情况,你可以使用类似上面的东西。

您可以通过inheritancePromise来处理new事物:

 class MyPromise extends Promise { constructor(ms, callback) { // We need to support being called with no milliseconds // value, because the various Promise methods (`then` and // such) correctly call the subclass constructor when // building the new promises they return. // This code to do it is ugly, could use some love, but it // gives you the idea. let haveTimeout = typeof ms === "number" && typeof callback === "function"; let init = haveTimeout ? callback : ms; super((resolve, reject) => { init(resolve, reject); if (haveTimeout) { setTimeout(() => { reject("Timed out"); }, ms); } }); } } 

用法:

 let p = new MyPromise(300, function(resolve, reject) { // ... }); p.then(result => { }) .catch(error => { }); 

现场示例:

 // Uses var instead of let and non-arrow functions to try to be // compatible with browsers that aren't quite fully ES6 yet, but // do have promises... (function() { "use strict"; class MyPromise extends Promise { constructor(ms, callback) { var haveTimeout = typeof ms === "number" && typeof callback === "function"; var init = haveTimeout ? callback : ms; super(function(resolve, reject) { init(resolve, reject); if (haveTimeout) { setTimeout(function() { reject("Timed out"); }, ms); } }); } } var p = new MyPromise(100, function(resolve, reject) { // We never resolve/reject, so we test the timeout }); p.then(function(result) { snippet.log("Resolved: " + result); }).catch(function(reject) { snippet.log("Rejected: " + reject); }); })(); 
 <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 --> <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script> 

虽然也许不支持承诺超时,但你可以承诺承诺:

 var race = Promise.race([ new Promise(function(resolve){ setTimeout(function() { resolve('I did it'); }, 1000); }), new Promise(function(resolve, reject){ setTimeout(function() { reject('Timed out'); }, 800); }) ]); race.then(function(data){ console.log(data); }).catch(function(e){ console.log(e); }); 

这是一个稍微旧的问题,但当我正在寻找如何超时的承诺时,我偶然发现了这个问题。
虽然所有的答案都很好,但是我发现使用Promises的蓝鸟实现作为处理超时最简单的方法:

 var Promise = require('bluebird'); var p = new Promise(function(reject, resolve) { /.../ }); p.timeout(3000) //make the promise timeout after 3000 milliseconds .then(function(data) { /handle resolved promise/ }) .catch(Promise.TimeoutError, function(error) { /handle timeout error/ }) .catch(function(error) { /handle any other non-timeout errors/ }); 

正如你所看到的,这比其他提议的解决scheme要less得多。 我想我会把它放在这里,让人们更容易find它:)

顺便说一句,我不是以任何方式参与蓝鸟项目,只是发现这个特别的解决scheme非常整齐。

要为任何现有的承诺添加超时,您可以使用:

 const withTimeout = (millis, promise) => { const timeout = new Promise((resolve, reject) => setTimeout( () => reject(`Timed out after ${millis} ms.`), millis)); return Promise.race([ promise, timeout ]); }; 

后来:

 await withTimeout(5000, doSomethingAsync());