1112 字
6 分钟

定时器的注意要点

欢迎来到我的博客!#

使用 Markdown 格式编写。

今天学到了什么#

  • JavaScript的执行顺序
  • 定时器的注意要点
  • 案例易错点

JavaScript的执行顺序#

JavaScript 代码(在主线程中)默认是同步线性执行的(Single-threaded, Synchronous)。

简单直接的答案: 它是从上往下,严格等待上一行代码(或函数)彻底执行完毕后,才会执行下一行。 并不是“不用等第一个执行完,第二个就会开始”。

定时器的注意要点#

那这个怎么解释?不应该先等定时器函数执行完毕之后再输出。定时器的ID序号吗?

image-20260203190103566

这是一个非常棒的问题!看似矛盾,其实是因为定时器(setInterval/setTimeout)是 JavaScript 中的特例,它们属于**异步(Asynchronous)**操作。

让我把之前的“线性执行”再精确一下: JavaScript 主线程确实是线性往下走的,但遇到定时器时,它做的事情叫“定闹钟”,而不是“等闹钟响”。

刚才代码的实际执行过程:#

假设代码是这样的:

// 第一步:声明函数
function fn() {
console.log('一秒执行一次')
}
// 第二步:设置定时器
// 这一行代码的意思是:“浏览器,麻烦你帮我记个事,1秒后运行 fn”
// 浏览器说:“好,这个任务编号(ID)是 2,我记下了,你继续往下忙吧。”
let n = setInterval(fn, 1000)
// 注意:这里 JS **并没有** 停下来等1秒,它只是开启了这个开关,拿到 ID 就立刻走了。
// 第三步:打印 n
// 这一行紧接着第二步执行,中间几乎没有时间差。
// 此时 fn 还没运行(因为1秒还没到),但 ID 已经拿到了。
console.log(n) // 所以这里先打印了 2
// ... 主线程没事干了 ...
// 第四步(1秒后):
// 浏览器发现时间到了,把 fn 扔出来执行。
// console.log('一秒执行一次')

生活中的类比#

这就好比你去定外卖

  1. 你(JS主线程) 下单了(调用 setInterval)。
  2. App(浏览器) 立刻给你一个订单号 2(返回 ID n)。
  3. 你拿到订单号,立刻发朋友圈说“买了!订单号是 2”(执行 console.log(n))。
  4. 外卖员(异步任务) 在 30 分钟后才把饭送到(执行 fn,打印内容)。

你并没有坐在那里发呆等 30 分钟才拿到订单号,你是下单的一瞬间就拿到了,然后继续做别的事。

总结#

  • 普通代码(赋值、计算、循环):是从上往下,必须做完上一行才做下一行。
  • 定时器代码:是从上往下,但它的“做完”指的是**“闹钟定好了”**,而不是“闹钟响了”。所以它不会阻塞后面的代码。

案例易错点#

这个if判断能不能放在函数外面?

image-20260203190532782

不能放在外面。 如果放在外面,定时器就停不下来了。

原因还是刚才说的“同步执行”和“异步执行”的区别:

如果你把 if 放在外面(错误写法):#

let i = 5
let n = setInterval(function() {
i-- // 这是1秒后才会发生的事
console.log(i)
}, 1000)
// --- 主线程走到这里是“一瞬间”的事 ---
// 此时虽然其实启动了定时器,但甚至连第1秒都还没到
// 此时 i 还是 5
if (i === 0) {
clearInterval(n)
}
  1. 只执行一次:放在外面的代码,浏览器只会在页面刚打开时执行一次
  2. 判断时机不对:当浏览器执行到这个 if 的时候,定时器才刚刚定好,i 还是初始值 5
    • 浏览器心想:“5 === 0 吗?不等于。好,这个 if 我执行完了,以后如果不刷新页面,我再也不会看这行代码了。”
  3. 后果:虽然过一会 i 真的变成了 0,甚至变成了 -1, -2… 但因为那个 if 判断早就执行结束了,没人再去喊停了。

为什么必须放在里面?#

放在 function 里面,意味着:每过一秒钟,随着数字变化,都要重新审视一下:现在是不是到 0 了?

  • 第 1 秒:i 变成 4,判断一下,不是 0,继续。
  • 第 5 秒:i 变成 0,判断一下,是 0 了! -> 只有这时候才能根据最新的情况去关闭定时器。

赞助支持

如果这篇文章对你有帮助,欢迎赞助支持!

赞助
最后更新于 2026-02-03,距今已过 45 天

部分内容可能已过时

目录