🌐 Discover JavaScript Timers
setTimeout(): void
编写 JavaScript 代码时,你可能希望延迟函数的执行。
🌐 When writing JavaScript code, you might want to delay the execution of a function.
这是 setTimeout 的作用。你需要指定一个稍后执行的回调函数,以及一个用毫秒表示的延迟时间:
🌐 This is the job of setTimeout. You specify a callback function to execute later, and a value expressing how later you want it to run, in milliseconds:
setTimeout(() => { // runs after 2 seconds }, 2000); setTimeout(() => { // runs after 50 milliseconds }, 50);
此语法定义了一个新函数。你可以在其中调用任何其他函数,或者传入一个已有的函数名和一组参数:
🌐 This syntax defines a new function. You can call whatever other function you want in there, or you can pass an existing function name, and a set of parameters:
const myFunction = (firstParam, secondParam) => { // do something }; // runs after 2 seconds setTimeout(myFunction, 2000, firstParam, secondParam);
setTimeout 在 Node.js 中返回一个 Timeout 实例,而在浏览器中返回一个数字类型的定时器 ID。这个对象或 ID 可以用来取消已安排的函数执行:
const timeout = setTimeout(() => { // should run after 2 seconds }, 2000); // I changed my mind clearTimeout(timeout);
🌐 Zero delay
如果你将超时延迟指定为 0,回调函数将尽快执行,但会在当前函数执行之后:
🌐 If you specify the timeout delay to 0, the callback function will be executed as soon as possible, but after the current function execution:
setTimeout(() => { console.log('after '); }, 0); console.log(' before ');
这段代码将打印
🌐 This code will print
before after
通过在调度程序中排队函数,这特别有用,可以避免在密集任务上阻塞 CPU,并在执行繁重计算时执行其他函数。
🌐 This is especially useful to avoid blocking the CPU on intensive tasks and let other functions be executed while performing a heavy calculation, by queuing functions in the scheduler.
一些浏览器(IE 和 Edge)实现了
setImmediate()方法,它具有完全相同的功能,但它不是标准方法,并且在其他浏览器上 不可用。不过,它是 Node.js 中的标准函数。
setInterval(): void
setInterval 是一个类似于 setTimeout 的函数,它的区别在于:它不会只执行一次回调函数,而是会在你指定的时间间隔(以毫秒为单位)内一直执行该函数:
setInterval(() => { // runs every 2 seconds }, 2000);
上面的函数每两秒运行一次,除非你用 clearInterval 告诉它停止,并传入 setInterval 返回的间隔 ID:
🌐 The function above runs every 2 seconds unless you tell it to stop, using clearInterval, passing it the interval id that setInterval returned:
const timeout = setInterval(() => { // runs every 2 seconds }, 2000); clearInterval(timeout);
通常会在 setInterval 回调函数内部调用 clearInterval,以便让它自动判断是否应该再次运行或停止。例如,这段代码会一直执行某些操作,除非 App.somethingIWait 的值为 arrived:
🌐 It's common to call clearInterval inside the setInterval callback function, to let it auto-determine if it should run again or stop. For example this code runs something unless App.somethingIWait has the value arrived:
const interval = setInterval(() => { if (App.somethingIWait === 'arrived') { clearInterval(interval); } // otherwise do things }, 100);
🌐 Recursive setTimeout
setInterval 会每隔 n 毫秒启动一次函数,而不会考虑函数何时执行完成。
如果一个函数总是花费相同的时间,那就没问题:
🌐 If a function always takes the same amount of time, it's all fine:
0 1000 2000 3000 | | | | | | | | | [██████████] | | | [exe script] | | | [██████████] | | | | [██████████] | | | [exe script] | | | [██████████] | | | | [██████████] | | | [exe script] | | | [██████████] |__________|___________|___________|____
也许函数需要不同的执行时间,具体取决于网络条件,例如:
🌐 Maybe the function takes different execution times, depending on network conditions for example:
0 1000 2000 3000 | | | | | | | | | [██████████] | | | [exe script] | | | [██████████] | | | | [████████████████████] | | [ execute script ] | | [████████████████████] | | | [██████████] | | | [exe script] | | | [██████████] |__________|___________|___________|____
也许一个长时间的执行会与下一个重叠:
🌐 And maybe one long execution overlaps the next one:
0 1000 2000 3000 4000 | | | | | | [████████████████████] | | | [ execute script ] | | | [████████████████████] | | | [███████████████████████████] | | [ execute script ] | | [███████████████████████████] | | | | [██████████████] | | | [execute script] | | | [██████████████] |__________|___________|___________|___________|__
要避免这种情况,你可以安排在回调函数完成时调用递归 setTimeout:
🌐 To avoid this, you can schedule a recursive setTimeout to be called when the callback function finishes:
const myFunction = () => { // do something setTimeout(myFunction, 1000); }; setTimeout(myFunction, 1000);
要实现这种情况:
🌐 to achieve this scenario:
0 1000 2000 3000 | | | | | [█████████████] | [█████████████] | [ exec script ]>──1s──<[ exec script ] | [█████████████] | [█████████████] | | | | |__________|____________|___________|__________
setTimeout 和 setInterval 可以在 Node.js 中使用,通过 Timers 模块。
Node.js 还提供了 setImmediate(),它会安排回调在事件循环的检查阶段执行。与 setTimeout(() => {}, 0) 不同,它通常不等同,因为它们的回调在事件循环的不同阶段执行,并且它们的执行顺序取决于执行上下文。
🌐 Node.js also provides setImmediate(), which schedules a callback to execute during the check phase of the event loop. Unlike setTimeout(() => {}, 0), it is not generally equivalent because their callbacks are executed in different phases of the event loop and their execution order depends on the execution context.