在promise中超时函数的最佳一般做法是啥[关闭]

Posted

技术标签:

【中文标题】在promise中超时函数的最佳一般做法是啥[关闭]【英文标题】:What is the best general practice to timeout a function in promise [closed]在promise中超时函数的最佳一般做法是什么[关闭] 【发布时间】:2015-09-05 08:36:50 【问题描述】:

使用超时承诺函数调用

我看到许多资源都提供了使用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]);

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

这听起来不错且易于使用。

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

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

我一直在寻找替代方法,但找不到本地 Promise 方法来执行此操作。

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

蓝鸟供应.timeout()

WinJS 也提供 .timeout()

Q还附带.timeout()

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

【问题讨论】:

鉴于 ES6 Promise 是不可取消的,除了race 处理延迟拒绝的任务之外,您无能为力。 我也通过可用的官方 ES6 Promise 功能进行了探索,也找不到其他类似的方式。 【参考方案1】:

这取决于你所说的超时是什么意思。

如果您希望函数停止,那么不会。

如果你只想停止等待,那么可以(在 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");
)]);

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);
&lt;div id="div"&gt;&lt;/div&gt;

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

Cancelable promises 在 ES6 中是一个有争议的话题,但提到的一些库确实提供了这个概念。

【讨论】:

通过“超时”一词,它可以推断在一段时间内未能产生输出的函数的输出将不再重要。因此,任何一种情况在使用方面都可能没有区别,因为无论函数是否允许在超时后运行,输出都不会被考虑在内。 (尽管两者完全不同)。 @TaoP.R. - 这假设一个没有副作用的功能。假设该功能播放音乐并在曲目完成后解决承诺。如果我们在 20 秒超时后启动第二个曲目,那么第一首曲目是否仅播放 20 秒或两个曲目是否相互重叠播放很重要。充其量,一个正在运行的函数会消耗 CPU,所以我认为最好清楚地了解想要的效果,而不是将 cancelingabandoning 视为相同。 确实非常好。但是,对于一般情况,超时可能只会触发“拒绝”信号,而不会潜在地终止正在进行的进程。如果开发人员愿意,应手动采取以防止不良行为。所以我们只考虑函数仍然异步执行但 Promise 不再等待它的情况。【参考方案2】:

本机 Promise.race 方法不会在实际 Promise 完成后清除超时 Promise 的计时器,因此该进程将等待直到超时 Promise 也完成。这意味着如果您将超时设置为 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;
    )
  ]);

【讨论】:

相关:github.com/github/fetch/issues/175#issuecomment-216791333 我很好奇你为什么要从内部承诺中返回计时器? 对此进行投票,因为如果您使用 jest 进行测试,它将挂起直到超时完成。这个解决方案可以防止这种情况

以上是关于在promise中超时函数的最佳一般做法是啥[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

(在表格中搜索)最佳做法是啥? [关闭]

创建链接以重置密码的最佳做法是啥? [关闭]

在 foreach 循环中使用 try-catch 块的最佳做法是啥? [关闭]

减小文件大小的最佳做法? [关闭]

R 包检查尚未运行的函数的参数的最佳做法是啥?

使用 ES6 的 Promise.all() 时限制并发的最佳方法是啥?