Pixiv - KiraraShss
1112 字
6 分钟
定时器的注意要点
欢迎来到我的博客!
使用 Markdown 格式编写。
今天学到了什么
- JavaScript的执行顺序
- 定时器的注意要点
- 案例易错点
JavaScript的执行顺序
JavaScript 代码(在主线程中)默认是同步且线性执行的(Single-threaded, Synchronous)。
简单直接的答案: 它是从上往下,严格等待上一行代码(或函数)彻底执行完毕后,才会执行下一行。 并不是“不用等第一个执行完,第二个就会开始”。
定时器的注意要点
那这个怎么解释?不应该先等定时器函数执行完毕之后再输出。定时器的ID序号吗?

这是一个非常棒的问题!看似矛盾,其实是因为定时器(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('一秒执行一次')生活中的类比
这就好比你去定外卖:
- 你(JS主线程) 下单了(调用
setInterval)。 - App(浏览器) 立刻给你一个订单号 2(返回 ID
n)。 - 你拿到订单号,立刻发朋友圈说“买了!订单号是 2”(执行
console.log(n))。 - 外卖员(异步任务) 在 30 分钟后才把饭送到(执行
fn,打印内容)。
你并没有坐在那里发呆等 30 分钟才拿到订单号,你是下单的一瞬间就拿到了,然后继续做别的事。
总结
- 普通代码(赋值、计算、循环):是从上往下,必须做完上一行才做下一行。
- 定时器代码:是从上往下,但它的“做完”指的是**“闹钟定好了”**,而不是“闹钟响了”。所以它不会阻塞后面的代码。
案例易错点
这个if判断能不能放在函数外面?

不能放在外面。 如果放在外面,定时器就停不下来了。
原因还是刚才说的“同步执行”和“异步执行”的区别:
如果你把 if 放在外面(错误写法):
let i = 5let n = setInterval(function() { i-- // 这是1秒后才会发生的事 console.log(i)}, 1000)
// --- 主线程走到这里是“一瞬间”的事 ---
// 此时虽然其实启动了定时器,但甚至连第1秒都还没到// 此时 i 还是 5if (i === 0) { clearInterval(n)}- 只执行一次:放在外面的代码,浏览器只会在页面刚打开时执行一次。
- 判断时机不对:当浏览器执行到这个
if的时候,定时器才刚刚定好,i还是初始值5。- 浏览器心想:“
5 === 0吗?不等于。好,这个if我执行完了,以后如果不刷新页面,我再也不会看这行代码了。”
- 浏览器心想:“
- 后果:虽然过一会
i真的变成了 0,甚至变成了 -1, -2… 但因为那个if判断早就执行结束了,没人再去喊停了。
为什么必须放在里面?
放在 function 里面,意味着:每过一秒钟,随着数字变化,都要重新审视一下:现在是不是到 0 了?
- 第 1 秒:i 变成 4,判断一下,不是 0,继续。
- …
- 第 5 秒:i 变成 0,判断一下,是 0 了! -> 只有这时候才能根据最新的情况去关闭定时器。
赞助支持
如果这篇文章对你有帮助,欢迎赞助支持!
最后更新于 2026-02-03,距今已过 45 天
部分内容可能已过时