如何在 Javascript 中实现“函数超时”——而不仅仅是“setTimeout”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8778718/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to implement a "function timeout" in Javascript - not just the 'setTimeout'
提问by sransara
How to implement a timeoutin Javascript, not the window.timeout
but something like session timeout
or socket timeout
- basically - a "function timeout
"
如何在 Javascript 中实现超时,而不是window.timeout
类似于session timeout
或socket timeout
- 基本上 - 一个“ function timeout
”
A specified period of time that will be allowed to elapse in a system before a specified event is to take place, unless another specified event occurs first; in either case, the period is terminated when either event takes place.
在指定事件发生之前,系统中允许经过的指定时间段,除非另一个指定事件先发生;在任何一种情况下,该期限在任一事件发生时终止。
Specifically, I want a javascript observing timer
that will observe the execution time of a function and if reached or going more than a specified time then the observing timer
will stop/notify the executing function.
具体来说,我想要一个 javascriptobserving timer
来观察函数的执行时间,如果达到或超过指定时间,observing timer
则将停止/通知正在执行的函数。
Any help is greatly appreciated! Thanks a lot.
任何帮助是极大的赞赏!非常感谢。
回答by jfriend00
I'm not entirely clear what you're asking, but I think that Javascript does not work the way you want so it cannot be done. For example, it cannot be done that a regular function call lasts either until the operation completes or a certain amount of time whichever comes first. That can be implemented outside of javascript and exposed through javascript (as is done with synchronous ajax calls), but can't be done in pure javascript with regular functions.
我不完全清楚你在问什么,但我认为 Javascript 不能按照你想要的方式工作,所以它无法完成。例如,常规函数调用不能持续到操作完成或一定时间,以先到者为准。这可以在 javascript 之外实现并通过 javascript 公开(就像同步 ajax 调用那样),但不能在具有常规函数的纯 javascript 中完成。
Unlike other languages, Javascript is single threaded so that while a function is executing a timer will never execute (except for web workers, but they are very, very limited in what they can do). The timer can only execute when the function finishes executing. Thus, you can't even share a progress variable between a synchronous function and a timer so there's no way for a timer to "check on" the progress of a function.
与其他语言不同,Javascript 是单线程的,因此当一个函数正在执行时,一个计时器将永远不会执行(除了 web 工作者,但他们能做的非常非常有限)。定时器只有在函数执行完毕后才能执行。因此,您甚至无法在同步函数和计时器之间共享进度变量,因此计时器无法“检查”函数的进度。
If your code was completely stand-alone (didn't access any of your global variables, didn't call your other functions and didn't access the DOM in anyway), then you could run it in a web-worker (available in newer browsers only) and use a timer in the main thread. When the web-worker code completes, it sends a message to the main thread with it's results. When the main thread receives that message, it stops the timer. If the timer fires before receiving the results, it can kill the web-worker. But, your code would have to live with the restrictions of web-workers.
如果你的代码是完全独立的(没有访问任何全局变量,没有调用你的其他函数,也没有访问 DOM),那么你可以在 web-worker 中运行它(在仅适用于较新的浏览器)并在主线程中使用计时器。当 web-worker 代码完成时,它会向主线程发送一条带有结果的消息。当主线程收到该消息时,它会停止计时器。如果计时器在收到结果之前触发,它可以杀死网络工作者。但是,您的代码必须忍受网络工作者的限制。
Soemthing can also be done with asynchronous operations (because they work better with Javascript's single-threaded-ness) like this:
Soemthing 也可以通过异步操作来完成(因为它们在 Javascript 的单线程中工作得更好),如下所示:
- Start an asynchronous operation like an ajax call or the loading of an image.
- Start a timer using
setTimeout()
for your timeout time. - If the timer fires before your asynchronous operation completes, then stop the asynchronous operation (using the APIs to cancel it).
- If the asynchronous operation completes before the timer fires, then cancel the timer with
clearTimeout()
and proceed.
- 启动异步操作,如 ajax 调用或图像加载。
- 使用
setTimeout()
超时时间启动计时器。 - 如果计时器在异步操作完成之前触发,则停止异步操作(使用 API 取消它)。
- 如果异步操作在计时器触发之前完成,则取消计时器
clearTimeout()
并继续。
For example, here's how to put a timeout on the loading of an image:
例如,这里是如何在加载图像时设置超时:
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;
}
回答by Robert
You could execute the code in a web worker. Then you are still able to handle timeout events while the code is running. As soon as the web worker finishes its job you can cancel the timeout. And as soon as the timeout happens you can terminate the web worker.
您可以在 Web Worker 中执行代码。然后您仍然可以在代码运行时处理超时事件。一旦网络工作者完成其工作,您就可以取消超时。一旦超时发生,您就可以终止网络工作者。
execWithTimeout(function() {
if (Math.random() < 0.5) {
for(;;) {}
} else {
return 12;
}
}, 3000, function(err, result) {
if (err) {
console.log('Error: ' + err.message);
} else {
console.log('Result: ' + result);
}
});
function execWithTimeout(code, timeout, callback) {
var worker = new Worker('data:text/javascript;base64,' + btoa('self.postMessage((' + String(code) + '\n)());'));
var id = setTimeout(function() {
worker.terminate();
callback(new Error('Timeout'));
}, timeout);
worker.addEventListener('error', function(e) {
clearTimeout(id);
callback(e);
});
worker.addEventListener('message', function(e) {
clearTimeout(id);
callback(null, e.data);
});
}
回答by freakish
You can achieve this only using some hardcore tricks. Like for example if you know what kind of variable your function returns (note that EVERYjs function returns something, default is undefined
) you can try something like this: define variable
您只能使用一些核心技巧来实现这一点。例如,如果你知道你的函数返回什么样的变量(注意每个js 函数都会返回一些东西,默认是undefined
)你可以尝试这样的事情:定义变量
var x = null;
and run test in seperate "thread":
并在单独的“线程”中运行测试:
function test(){
if (x || x == undefined)
console.log("Cool, my function finished the job!");
else
console.log("Ehh, still far from finishing!");
}
setTimeout(test, 10000);
and finally run function:
最后运行函数:
x = myFunction(myArguments);
This only works if you know that your function either does not return any value (i.e. the returned value is undefined
) or the value it returns is always "not false", i.e. is not converted to false
statement (like 0
, null
, etc).
这只有当你知道你的函数或者不返回任何值(即返回的值是工程undefined
),或者它返回的值始终为“不假”,即没有转化为false
语句(如0
,null
等)。
回答by Hans Bouwmeester
I realize this is an old question/thread but perhaps this will be helpful to others.
我意识到这是一个老问题/线程,但也许这对其他人有帮助。
Here's a generic callWithTimeout
that you can await
:
这是一个通用的callWithTimeout
,你可以await
:
export function callWithTimeout(func, timeout) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => reject(new Error("timeout")), timeout)
func().then(
response => resolve(response),
err => reject(new Error(err))
).finally(() => clearTimeout(timer))
})
}
Tests/examples:
测试/示例:
export function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
const func1 = async () => {
// test: func completes in time
await sleep(100)
}
const func2 = async () => {
// test: func does not complete in time
await sleep(300)
}
const func3 = async () => {
// test: func throws exception before timeout
await sleep(100)
throw new Error("exception in func")
}
const func4 = async () => {
// test: func would have thrown exception but timeout occurred first
await sleep(300)
throw new Error("exception in func")
}
Call with:
致电:
try {
await callWithTimeout(func, 200)
console.log("finished in time")
}
catch (err) {
console.log(err.message) // can be "timeout" or exception thrown by `func`
}
回答by Rogel Garcia
Share a variable between the observing timer
and the executing function
.
在observing timer
和之间共享一个变量executing function
。
Implement the observing timer
with window.setTimeout
or window.setInterval
. When the observing timer
executes, it sets an exitvalue to the shared variable.
实现observing timer
withwindow.setTimeout
或window.setInterval
。当observing timer
执行时,它设置一个出口值到共享变量。
The executing function
constantly checks for the variable value.. and returns if the exitvalue is specified.
的executing function
用于可变值不断检查..并返回,如果出口被指定的值。