是否有返回 ES6 承诺的 setTimeout 版本?

Posted

技术标签:

【中文标题】是否有返回 ES6 承诺的 setTimeout 版本?【英文标题】:Is there a version of setTimeout that returns an ES6 promise? 【发布时间】:2016-03-19 05:51:38 【问题描述】:

类似于this question,但我不想问一般的promise是如何工作的,我特别想知道:

将setTimeout 包装在返回Promise 的东西中的标准/最佳方法是什么?我正在考虑类似于 Angular 的 $timeout function,但不是 Angular 特定的。

【问题讨论】:

没看到这个,我是这样做的 -> jsfiddle.net/vLtrtoLL Bluebird 承诺库有 Promise.delay() 【参考方案1】:

在浏览器中

首先没有 - 没有内置的。许多增强 ES2015 承诺的库,例如 bluebird 鞭子。

我认为另一个答案将执行函数和延迟混为一谈,它还会产生无法取消的超时。我会简单地写成:

function delay(ms)
    var ctr, rej, p = new Promise(function (resolve, reject) 
        ctr = setTimeout(resolve, ms);
        rej = reject;
    );
    p.cancel = function() clearTimeout(ctr); rej(Error("Cancelled"));
    return p; 

那么你可以这样做:

delay(1000).then(/* ... do whatever */);

或者

 doSomething().then(function() return delay(1000); ).then(doSomethingElse);

如果我们只想要 ES2015 中的基本功能,那就更简单了:

let delay = ms => new Promise(r => setTimeout(r, ms));

在节点中

您可以在setTimeout 上使用util.promisify 来获取delay 函数——这意味着您不必再使用new Promise 构造函数。

【讨论】:

美丽的答案。我很高兴我现在问了这个问题。 这个例子的问题:解析时也应该调用clearTimeout 当我尝试上述@Benjamin Gruenbaum 答案的任一版本时,then( 之后的代码立即执行而不等待延迟。示例delay(2000).then(console.log("then 1")).then(delay(2000).then(console.log("then 2"))); 立即打印“then 1”“then 2”而不延迟,两秒后程序结束。 @TimothyVann then 接受一个函数——而不是一个承诺。【参考方案2】:

这是我的实现方式:

function delay(duration, func) 
  var args = Array.prototype.slice.call(arguments, 2);

  return new Promise(function (resolve) 
    setTimeout(function () 
      resolve(func.apply(null, args));
    , duration);
  );

(有意选择的ES5语法)

但也许已经有一个通用库可以做到这一点,或者有更好的方法来做到这一点。

【讨论】:

这看起来不错。这是一段如此短的代码,我真的看不出在库中挖掘类似的东西有什么意义。 不要那样做。您应该在最低级别进行承诺 - setTimeout - 并将 func 移动到承诺回调中,其中的异常将被正确捕获。【参考方案3】:

如果您需要类似于clearTimeout 的正确取消承诺超时 - 直接从setTimeout 返回承诺并不方便。特别是在 try...finally 块中与 ES7 async / await 一起使用时。最好有单独的变量来进行超时操作。我已经将这种方法实现为微小的await-timeout 包。它的工作原理如下:

import Timeout from 'await-timeout';

async function foo() 
  const timeout = new Timeout();
  try 
    const fetchPromise = fetch('https://example.com');
    const timerPromise = timeout.set(1000).then(() => console.log('Timeout!'));
    await Promise.race([fetchPromise, timerPromise]);
   finally 
    timeout.clear();
  

在此示例中,如果获取成功或任何错误,超时肯定会被清除,并且不会调用console.log('Timeout!')

【讨论】:

这毫无意义。您只是在等待超时后才清除超时...... 已修复。谢谢!

以上是关于是否有返回 ES6 承诺的 setTimeout 版本?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 setTimeout 做出承诺

你如何将 setTimeout 包装在一个承诺中[重复]

在承诺链上使用 setTimeout

类函数中的 Javascript ES6 承诺

ES5 与 ES6 承诺

使用返回承诺的函数过滤数组