在promise中超时函数的最佳通用做法是什么?

Tao*_*oPR 15 javascript promise ecmascript-6 es6-promise

使用超时实现函数调用

我已经看到许多资源提供Promise.race了在给定时间段内使用超时函数调用的类似示例.这是如何Promise.race在实践中使用的一个很好的例子.这是一些示例代码:

function doWithinInterval(func, timeout) {
    var promiseTimeout = new Promise(function (fulfill, reject) {
       // Rejects as soon as the timeout kicks in
       setTimeout(reject, timeout);
    });
    var promiseFunc = new Promise(function (fulfill, reject) {
        var result = func(); // Function that may take long to finish
        // Fulfills when the given function finishes
        fulfill(result);
    });

    return Promise.race([promiseTimeout, promiseFunc]);
}
Run Code Online (Sandbox Code Playgroud)

上面使用的简单方法Promise.race一旦超时func完成就会拒绝承诺.否则,一旦func函数在超时间隔之前完成,项目就会完成.

这听起来不错,易于使用.

但是,这是在Promise中使用超时的最佳做法吗?

当然,如果我们想使用Promises为函数调用设置超时,可以使用上面的方法.这些行动似乎仍然是一个很好的承诺.但是,这被认为是在Promise中使用超时的好方法吗?如果没有,使用它的缺点是什么?

我正在寻找替代方法,但找不到本机的Promise方法来做到这一点.

相反,一些外部Promise库提供timeout如下功能:

但是,Promise.timeout()似乎不是标准ECMAScript 6 API的一部分(如果我错了,请纠正我).是否有任何推荐的方法来处理ES6 Promises原生的超时?

jib*_*jib 13

这取决于你的超时意味着什么.

如果你希望函数停止,那么没有.

如果你只是想停止等待它,那么是(快速在ES6中掀起):

var wait = ms => new Promise(resolve => setTimeout(resolve, ms));
var timeout = (p, ms) => Promise.race([p, wait(ms).then(() => {
    throw new Error("Timeout after " + ms + " ms");
})]);
Run Code Online (Sandbox Code Playgroud)

var wait = ms => new Promise(resolve => setTimeout(resolve, ms));
var timeout = (p, ms) => Promise.race([p, wait(ms).then(() => {
  throw new Error("Timeout after " + ms + " ms");
})]);

// Example:

var log = msg => div.innerHTML += "<p>" + msg + "</p>";
var failed = e => log(e.toString() + ", line " + e.lineNumber);

log("Waiting 5 seconds...");
timeout(wait(5000), 2000)
.then(() => log("...Done."))
.catch(failed);
Run Code Online (Sandbox Code Playgroud)
<div id="div"></div>
Run Code Online (Sandbox Code Playgroud)

如果你想取消操作(让它停止),那么希望该操作附带一个API来取消它,你应该使用它,因为ES6的承诺不是控制界面.

可取消的承诺在ES6中是一个有争议的话题,但提到的一些图书馆确实提供了这个概念.

  • @ TaoP.R. - 这假设一个没有副作用的功能.假设该功能播放音乐并在曲目完成后解析承诺.如果我们在20秒超时之后启动第二首曲目,那么第一首曲目是否只播放20秒或者两首曲目是否相互重叠是很重要的.最好的情况是,运行功能消耗CPU,所以我认为最好清楚所需的效果而不是*取消*和*放弃*相同. (2认同)

xpe*_*int 9

在实际的promise完成后,本机Promise.race方法不会清除超时保证的计时器,因此进程将等到超时保证也完成.这意味着如果您将超时设置为1h并且我们的承诺在1分钟后完成,则该过程将在退出之前等待59分钟.

请改用此方法:

export function race({promise, timeout, error}) {
  let timer = null;

  return Promise.race([
    new Promise((resolve, reject) => {
      timer = setTimeout(reject, timeout, error);
      return timer;
    }),
    promise.then((value) => {
      clearTimeout(timer);
      return value;
    })
  ]);
}
Run Code Online (Sandbox Code Playgroud)

  • 我很好奇你为什么要从内心的承诺中返回计时器? (2认同)