1.1 JavaScript 是单线程的
JavaScript 是单线程运行的,从上到下执行。
1.2 任务队列
任务队列分为同步任务和异步任务。执行过程中,异步任务要挂起,先执行同步任务,所有同步任务执行完成后,才会执行异步任务。
异步任务包含:
- setTimeout 和 setInterval
- DOM 事件(click 等)
- ES6 中的 Promise
例题1:
以下代码的输出结果:
1 | console.log(1); |
解释:考察同步任务和异步任务的优先顺序。setTimeout/setTimeInterval
是异步任务,console.log
是同步任务。
例题2:
以下代码的输出结果:
1 | console.log('A'); |
解释:考察同步任务和异步任务的优先顺序。因为均为同步任务,执行 while
语句时无法结束循环,因此不能执行 console.log('B')
的语句。
例题3:
以下代码的输出结果:
1 | console.log('A'); |
解释:考察同步任务和异步任务的优先顺序。
例题4:
以下代码的输出结果:
for(var i=0; i<4; i++) {
setTimeout(function(){
console.log(i);
},0);
}
// 答案:4 4 4 4
解释:考察异步队列的任务插入时间。同步队列执行完成后执行异步队列,但异步任务只有到达执行时间,才会将任务放在异步队列中。因此在本题目中,当同步队列(for 循环)执行完成时,异步队列仍为空。setTimeout
的延迟时间为 1000ms,当 1000ms 后,Timer 定时器才会将函数题扔进异步队列中执行。
1.3 事件循环(Event Loop)
- 运行栈:用于存放同步任务
- 任务队列:用于存放异步任务
代码解析过程:
浏览器引擎识别 setTimeout 为异步任务,因此 Timer 模块将该语句从运行栈中取出,等到延迟时间后,将其放到任务队列中。
当运行栈(同步队列)已经为空,再从异步队列中取出任务到运行栈中执行。执行完成后,运行栈为空,再重复循环该过程。这一过程就是事件循环。