一道简单面试题理解JS事件机制(+1白话讲解)

1,180 阅读2分钟

定义

  1. 同步: 一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去
  2. 异步: 进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率
  3. 线程: 线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位。指运行中的程序的调度单位
  4. 单线程: 单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。单线程就是进程里只有一个线程

问题

console.log(100)
setTimeout(function () {
    console.log(200)
}, 0)
console.log(300)
输出:
// 100
// 300
// 200

解析

JS为单线程, 但是任务执行分为同步任务和异步任务

代码中console.log为同步任务, setTimeout为异步任务(这些基础东西就不过多解释了)

为了方便理解,我们可以认为JS这条单线程中有两条事件队列, 一条为同步队列(主事件大循环 Event Loop),一条为异步队列,同步任务在同步队列中依次执行,异步任务在异步队列中依次执行,并且这两个队列是同时执行的。但是,JavaScript引擎只会执行同步队列中的任务,那么异步队列中的任务什么时候执行呢?

JavaScript引擎会不断遍历同步队列,当同步队列为空时,会将异步队列中执行完毕的异步事件的回调函数放入同步队列执行。

回顾

现在让我们回来看看上面的面试题就很容易理解了,同步队列中console.log(100)和console.log(300)执行后,console.log(200)被推入同步队列执行,所以结果依次为100-> 300->200

PS: setTimeout(fun, 0)中的0不是立即执行的意思, 而是同步队列为空时立即将fun推入同步队列

额外

var flag = 1
setTimeout(function(){
    flag = 0
}, 0)
while(flag){
    console.log('running')
}

结果是什么?

答案为死循环,因为while(flag)中的代码将一直在同步队列中执行,而flag = 0没有机会被推入同步队列