About JavaScript Timers

JavaScript timers are a great feature for implementing looping behaviors or even triggering delayed actions. Timers can provide support for whatever time-based logic you have. There are two timer functions in JavaScript: setTimeoutand setInterval. Let's see what timers are and how they work.

Key Points About Timers

Before diving into the specifics of timers, there are a few very key points to keep in mind.

not entirely accurate

A timer either triggers an action after a certain number of seconds, or repeats an action every time the specified timeout elapses. However, while the expectation might be that they are accurate to the second, this is not the case.

The specification for these timers states that they will use a time parameter (such as a specified number of seconds) as the minimum wait time. But if there are other tasks that need to be done first, they will definitely take longer.

This only becomes a problem if your logic relies on precise time measurement, such as having a clock count seconds via a setIntervalcallback .

async function

This means they don't stop the program flow until they are done. Even if specified 0as a timeout value, their behavior is still asynchronous.

This means that these functions will add a reference to the function they want to fire into the event loop, so even if specified on the timeout value 0, the reference will be queued after everything that happens next.

setTimeout

setTimeoutFunctions are probably the easiest to understand because the main goal is to trigger a function after a few seconds, which will only be executed once.

The parameters of this function are as follows:

  • Function reference to execute: This is the code logic that will be triggered when the time comes.
  • Number of seconds to wait before function execution
  • All other arguments are then passed to the executed function in the same order.

The code below will print after 3seconds Hello World:

setTimeout(console.log, 3000, "Hello", "World");
复制代码

is equivalent to the following code:

setTimeout(
    (strHello, strWorld) => {
        console.log(strHello, strWorld);
    },
    3000,
    "Hello",
    "World"
);
复制代码

setTimeoutis a special type of asynchronous function, so whatever code is written after it will be executed before the function is triggered, as follows:

console.log("执行了第 1 行代码");
setTimeout(() => {
    console.log("执行了第 3 行代码");
}, 1000);
console.log("执行了第 5 行代码");
console.log("执行了第 6 行代码");
setTimeout(function () {
    console.log("执行了第 8 行代码");
}, 0);
console.log("执行了第 10 行代码");
复制代码

The output results are as follows:

执行了第 1 行代码
执行了第 5 行代码
执行了第 6 行代码
执行了第 10 行代码
执行了第 8 行代码
执行了第 3 行代码
复制代码

Note how lines 3 and 8 are executed last, even though the timeout for line 8 is 0.

在讨论 setTimeout 之前,如果设置超时值然后意识到必须停止它会发生什么?可以定义一个变量保存 setTimeout 的返回值(计时器 ID),则可以使用 clearTimeout 函数在超时之前停止计时器。

console.log("执行了第 1 行代码");
const timerId = setTimeout(() => {
    console.log("执行了第 3 行代码");
}, 1000);
console.log("执行了第 5 行代码");
clearTimeout(timerId);
console.log("执行了第 6 行代码");
setTimeout(function () {
    console.log("执行了第 8 行代码");
}, 0);
console.log("执行了第 10 行代码");
复制代码

执行结果如下,少了一个定时器的输出:

执行了第 1 行代码
执行了第 5 行代码
执行了第 6 行代码
执行了第 10 行代码
执行了第 8 行代码
复制代码

setInterval

setInterval 函数与 setTimeout 非常相似,但它不是只触发一次函数,而是一直触发函数直到停止。

此函数的签名与 setInterval 函数的签名完全相同,所有参数的也相同。

const names = ["刘备", "关羽", "张飞", "赵云", "黄忠"];

function sayHi(list) {
    let name = list[Math.round(Math.random() * 10) % 4];
    console.log("你好!", name);
}
console.log("蜀汉五虎将");
const intervalID = setInterval(sayHi, 1000, names);

setTimeout(() => {
    clearTimeout(intervalID);
}, 4000);
复制代码

上面的代码将启动一个每 1 秒触发一次的循环,当它触发时,将选择一个随机名称并打印字符串 你好! <name>。设置了 4 秒的超时时间,通过调用 clearTimeout 函数来结束无限循环。当然,也可以使用 clearInterval 函数,但由于它们使用相同的计时器池,可以互换使用它们。

区别

setTimeout 仅触发一次表达式,而 setInterval 在给定的时间间隔后保持定期触发表达式(除非手动终止)。

使用场合

除了执行定时操作,结合 Promise 方法,结合 setTimeout 可以实现休眠功能。

const sleep = (ms) => {
    return new Promise((resolve) => setTimeout(resolve, ms));
};
const asyncFoo = async () => {
    await sleep(2000);
    console.log("  等待2秒输出");
    await sleep(1000);
    console.log("    等待1秒输出");
};
console.log("开始执行");
asyncFoo();
复制代码

Promise 结合 setInterval 可以实现一些数据的最大检测次数,如某个数据通过API验证,验证结果无法给出正常结果,超过一定次数提示错误。

const fakeApiCheck = async () => {
    console.log("检查中...");
    return Math.random() > 0.8;
};
const asyncInterval = async (callback, ms, triesLeft = 5) => {
    return new Promise((resolve, reject) => {
        const interval = setInterval(async () => {
            if (await callback()) {
                resolve();
                clearInterval(interval);
            } else if (triesLeft <= 1) {
                reject();
                clearInterval(interval);
            }
            triesLeft--;
        }, ms);
    });
};
const dataCheck = async () => {
    try {
        await asyncInterval(fakeApiCheck, 500);
    } catch (e) {
        console.log("验证错误");
    }
    console.log("验证完成!");
};
dataCheck();
复制代码

总结

计时器是生成重复或延迟行为的绝佳函数,它们非常有用,尤其是当必须在某些基于时间的条件下与其他服务进行交互时。超时和间隔都可以在使用 clearInterval 或者 clearTimeout 函数触发之前强制停止。

おすすめ

転載: juejin.im/post/7194022475880431676