探索 JavaScript 定时器

¥Discover JavaScript Timers

setTimeout()

编写 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 返回定时器 ID。这通常不使用,但你可以存储此 ID,并在要删除此计划函数执行时清除它:

¥setTimeout returns the timer id. This is generally not used, but you can store this id, and clear it if you want to delete this scheduled function execution:

const id = setTimeout(() => {
  // should run after 2 seconds
}, 2000);

// I changed my mind
clearTimeout(id);

零延迟

¥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 中的标准函数。

¥Some browsers (IE and Edge) implement a setImmediate() method that does this same exact functionality, but it's not standard and unavailable on other browsers. But it's a standard function in Node.js.

setInterval()

setInterval 是一个类似于 setTimeout 的函数,但有区别:它不会运行一次回调函数,而是会按照你指定的特定时间间隔(以毫秒为单位)永远运行它:

¥setInterval is a function similar to setTimeout, with a difference: instead of running the callback function once, it will run it forever, at the specific time interval you specify (in milliseconds):

setInterval(() => {
  // runs every 2 seconds
}, 2000);

除非你使用 clearInterval 告诉它停止,否则上述函数每 2 秒运行一次,并将 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 id = setInterval(() => {
  // runs every 2 seconds
}, 2000);

clearInterval(id);

通常在 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);

递归 setTimeout

¥Recursive setTimeout

setInterval 每 n 毫秒启动一个函数,而不考虑函数何时完成执行。

¥setInterval starts a function every n milliseconds, without any consideration about when a function finished its execution.

如果一个函数总是花费相同的时间,那就没问题:

¥If a function always takes the same amount of time, it's all fine:

setInterval working fine

也许函数需要不同的执行时间,具体取决于网络条件,例如:

¥Maybe the function takes different execution times, depending on network conditions for example:

setInterval varying duration

也许一个长时间的执行会与下一个重叠:

¥And maybe one long execution overlaps the next one:

setInterval overlapping

要避免这种情况,你可以安排在回调函数完成时调用递归 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:

Recursive setTimeout

setTimeoutsetInterval 可通过 定时器模块 在 Node.js 中使用。

¥setTimeout and setInterval are available in Node.js, through the Timers module.

Node.js 还提供了 setImmediate(),这相当于使用 setTimeout(() => {}, 0),主要用于与 Node.js 事件循环配合使用。

¥Node.js also provides setImmediate(), which is equivalent to using setTimeout(() => {}, 0), mostly used to work with the Node.js Event Loop.