2015-10-19 41 views
9

“超时间隔”的良好模式我正在编写一些代码,每N毫秒轮询一个资源,这应该在M秒后超时。我希望整个事情都是尽可能使用蓝鸟的承诺。到目前为止,我提出的解决方案使用节点间隔,可取消蓝鸟许诺和蓝鸟超时功能。使用Promises

我想知道是否有更好的方法来做蓝鸟和一般的承诺超时间隔?主要是通过确保间隔停止在这一点,永远不会无限期地继续下去。

var Promise = require('bluebird'); 

function poll() { 
    var interval; 

    return new Promise(function(resolve, reject) { 
    // This interval never resolves. Actual implementation could resolve. 
    interval = setInterval(function() { 
     console.log('Polling...') 
    }, 1000).unref(); 
    }) 
    .cancellable() 
    .catch(function(e) { 
     console.log('poll error:', e.name); 
     clearInterval(interval); 
     // Bubble up error 
     throw e; 
    }); 
} 

function pollOrTimeout() { 
    return poll() 
    .then(function() { 
     return Promise.resolve('finished'); 
    }) 
    .timeout(5000) 
    .catch(Promise.TimeoutError, function(e) { 
     return Promise.resolve('timed out'); 
    }) 
    .catch(function(e) { 
     console.log('Got some other error'); 
     throw e; 
    }); 
} 

return pollOrTimeout() 
    .then(function(result) { 
    console.log('Result:', result); 
    }); 

输出:

Polling... 
Polling... 
Polling... 
Polling... 
poll error: TimeoutError 
Result: timed out 

回答

5

我会做这样的事情 -

function poll() { 
    return Promise.resolve().then(function() { 
    console.log('Polling...'); 
    if (conditionA) { 
     return Promise.resolve(); 
    } else if (conditionB) { 
     return Promise.reject("poll error"); 
    } else { 
     return Promise.delay(1000).then(poll); 
    } 
    }) 
    .cancellable() 
} 

另外要注意的Promise constructor anti-pattern

+1

不错。你将如何完成这个时间间隔?看起来像是抛出错误的唯一出路。我知道Promise构造函数是一种反模式,但在这种情况下它似乎很适合(与事件+ Promises相同,但这是另一个主题)。 – Chris911

+0

好吧,现在我明白你的问题。检查我的编辑。 – vinayr

+0

是的,这是有效的。谢谢并接受答案。 – Chris911

1

刘若英Wooller做一个很好的点:

警告:不幸的是,递归在这样的JavaScript将最终达到饱和调用堆栈,并导致内存不足异常

即使不例外,这是浪费的空间,以及异常的风险可能会延长投票延期。

我认为这是重要的,足以喜欢的setInterval:

var myPromise = new Promise((resolve, reject) => { 
    var id = window.setInterval(() => { 
     try { 
      if (conditionA) { 
       window.clearInterval(id); 
       resolve("conditionA"); 
      } else if (conditionB) { 
       throw new Error("conditionB!"); 
      } 
     } catch(e) { 
      window.clearInterval(id); 
      reject(e); 
     } 
    }, 1000); 
}); 

有迹象表明,满足这一要求,其中我喜欢promise-waitfor最好的几个NPM包。它长38行,完成这项工作。

var myPromise = waitFor(() => { 
    if(conditionA) return true; 
    if(conditionB) throw new Error("conditionB!"); 
    return false; 
}); 
+0

如果(conditionA)是一个承诺,你能向我解释如何实现这一点吗?我永远无法逃避承诺链,在waitFor()中返回一个简单的'true'或'false'。 – NZHammer

+1

随时为'conditionA'是一个承诺添加一个单独的问题。可能解决方案涉及'Promise.race'。 –

+0

我读过如果你的投票比你的setinverval运行时间更长,它会建立队列。然后当它完成时,它必须处理队列。并且最好使用setTimeout和递归来启动另一个setTimeout。 – TamusJRoyce