setTimeout 运行机制
理解 setTimeout 的执行时机和 JavaScript 事件循环机制
问题
为什么 setTimeout(fn, 0) 不会立即执行?理解 setTimeout 的运行机制。
解答
一个例子
console.log(1);
setTimeout(function () {
console.log(2);
}, 0);
console.log(3);
输出结果是:1 3 2
无论 setTimeout 的延迟时间是 0 还是 1000,结果都是先输出 3 后输出 2。这涉及到 JavaScript 的运行机制。
JavaScript 单线程
JavaScript 引擎是单线程执行的,浏览器中只有一个 JS 线程在运行程序(主线程)。所有任务分为两种:
同步任务:在主线程上排队执行,前一个任务执行完才能执行下一个。
异步任务:不进入主线程,而是进入任务队列(task queue)。只有主线程空闲时,才会从任务队列中取出异步任务执行。
运行机制
- 所有同步任务在主线程上执行,形成执行栈(Call Stack)
- 异步任务有了运行结果后,在任务队列中放置一个事件
- 执行栈中的同步任务执行完毕后,系统读取任务队列,将对应的异步任务放入执行栈开始执行
- 主线程不断重复第 3 步(Event Loop)
setTimeout 的执行时机
setTimeout 将指定的代码移出本次执行,等到下一轮 Event Loop 时检查是否到了指定时间。如果到了就执行,否则继续等待。
这意味着 setTimeout 指定的代码必须等到本次执行的所有同步代码都执行完才会执行。
关键点
- JavaScript 是单线程执行,通过事件循环实现异步
- setTimeout 是异步任务,会被放入任务队列而不是立即执行
- 即使延迟时间设为 0,也要等当前执行栈的同步任务全部完成
- 主线程会不断循环检查任务队列,这就是 Event Loop
目录