如何在Javascript中实现"函数超时" - 而不仅仅是'setTimeout'

sra*_*ara 11 javascript timeout

如何在Javascript中实现超时,而不是window.timeoutsession timeout或者socket timeout- 基本上 - 一个" function timeout"

除非先发生另一个指定事件,否则将在指定事件发生之前允许在系统中经过的指定时间段; 在任何一种情况下,当任一事件发生时,期限终止.

具体来说,我想要一个observing timer观察函数执行时间的javascript ,如果达到或超过指定时间,observing timer则会停止/通知执行函数.

任何帮助是极大的赞赏!非常感谢.

jfr*_*d00 12

我并不完全清楚你在问什么,但我认为Javascript不能按你想要的方式工作,所以无法完成.例如,无法执行常规函数调用,直到操作完成或持续一定时间(以先到者为准).这可以在javascript之外实现并通过javascript公开(与同步ajax调用一样),但不能在具有常规函数的纯javascript中完成.

与其他语言不同,Javascript是单线程的,因此当一个函数执行时,计时器将永远不会执行(除了Web worker,但它们在他们能做的事情上非常非常有限).定时器只能在函数完成执行时执行.因此,您甚至无法在同步函数和计时器之间共享进度变量,因此计时器无法"检查"函数的进度.

如果你的代码是完全独立的(没有访问你的任何全局变量,没有调用你的其他函数并且无论如何都没有访问过DOM),那么你可以在web-worker中运行它(可用于仅限较新的浏览器)并在主线程中使用计时器.当web-worker代码完成时,它会向主线程发送一条消息及其结果.当主线程收到该消息时,它会停止计时器.如果计时器在接收结果之前触发,则可以终止Web工作者.但是,您的代码必须遵守Web工作者的限制.

Soemthing也可以通过异步操作完成(因为它们可以更好地与Javascript的单线程一起使用),如下所示:

  1. 启动异步操作,如ajax调用或加载图像.
  2. 使用setTimeout()超时时间启动计时器.
  3. 如果计时器在异步操作完成之前触发,则停止异步操作(使用API​​取消它).
  4. 如果异步操作在计时器触发之前完成,则取消计时器clearTimeout()并继续.

例如,以下是如何在加载图像时设置超时:

function loadImage(url, maxTime, data, fnSuccess, fnFail) {
    var img = new Image();

    var timer = setTimeout(function() {
        timer = null;
        fnFail(data, url);
    }, maxTime);

    img.onLoad = function() {
        if (timer) {
            clearTimeout(timer);
            fnSuccess(data, img);
        }
    }

    img.onAbort = img.onError = function() {
        clearTimeout(timer);
        fnFail(data, url);
    }
    img.src = url;
}
Run Code Online (Sandbox Code Playgroud)


mar*_*tin 7

我的问题已被标记为与此问题重复,因此我想我会回答它,即使原始帖子已经有九年了。

我花了一段时间才明白 Javascript 单线程的含义(我仍然不确定我是否 100% 理解了),但以下是我如何使用 Promises 和回调解决类似的用例。它主要基于本教程

首先,我们定义一个timeout函数来包装 Promise:

const timeout = (prom, time, exception) => {
    let timer;
    return Promise.race([
        prom,
        new Promise((_r, rej) => timer = setTimeout(rej, time, exception))
    ]).finally(() => clearTimeout(timer));
}
Run Code Online (Sandbox Code Playgroud)

这是我想要超时的承诺:

const someLongRunningFunction = async () => {
  ...
  return ...;
}
Run Code Online (Sandbox Code Playgroud)

最后我是这样使用的。

const TIMEOUT = 2000;
const timeoutError = Symbol();
var value = "some default value";
try {
  value = await timeout(someLongRunningFunction(), TIMEOUT, timeoutError);
}
catch(e) {
  if (e === timeoutError) {
    console.log("Timeout");
  }
  else {
    console.log("Error: " + e);
  }
}
finally {
  return callback(value);
}
Run Code Online (Sandbox Code Playgroud)

这将调用该callback函数,并返回值someLongRunningFunction或超时时的默认值。您可以修改它以不同方式处理超时(例如抛出错误)。