js事件执行机制了解一下

326 阅读3分钟

这是我参与更文挑战的第3天,活动详情查看: 更文挑战

js单线程

js是一门浏览器的脚本语言,主要用于实现用户与浏览器的交互,以及操作dom,是一门单线程语言。由于js是单线程,所以所有的任务只能按顺序执行,执行完一个再执行下一个。可能有的人会问js为什么只能是单线程而不能是多线程呢?那我们现在就来做个假设,假设javascript是多线程语言,多线程是同时可以执行多个线程的操作,一个线程在某个DOM节点上执行添加的操作,另一个线程执行删除该节点的操作,js会再添加的同时进行删除操作,那么问题就来了,js是该执行添加还是该执行删除操作呢?因此,javascript的功能只能决定其是单线程语言。

同步任务和异步任务

js的任务分为同步任务和异步任务,同步任务会直接进入到主线程立即执行,而异步任务则会先进入到事件表(Event Table),等异步任务执行完成之后就会在Event Queue(事件队列)中注册回调函数,只有主线程任务全部完成后,才会执行Event Queue中的回调,js解析器会不断重复检查主线程的执行栈是否为空,然后再重复循环执行,这就是Event Loop(事件循环),如下图所示

宏任务和微任务

js任务还可分为宏任务和微任务

宏任务(macro-task)包含 script定时器相关的异步代码(setTimeOut、setInterval)I/O、UI Rendering

微任务(micro-task)包含 Promise.thenprocess.nextTick

注意:

  • 同步的代码会按照执行顺序依次执行,遇到异步代码的时候,宏任务的放到宏队列,微任务放到微队列,其中promise需要resolve或者reject才会执行then或者catch里面的内容。
  • 任务的执行顺序是宏任务-微任务-宏任务……,因为整个script其实就是一个宏任务,所以当js代码里的宏任务和微任务放入队列之后,就会先执行微任务再执行宏任务;前提是之前的任务执行完毕,如果存在嵌套关系,则会先执行完该任务再执行下一个任务,具体流程可参考下图
  • process.nextTick只能在node环境下运行

总结一下js的执行机制

先同步任务后异步任务
遇到new Promise先执行(Promise.then属于微任务)
先微任务后宏任务

举个栗子

<script>
    console.log('1')
    setTimeout(()=>{
        console.log('2')
    }, 0)
    new Promise((resolve, reject)=> {
        console.log('3')
        resolve()
    }).then(()=> {
        console.log('4')
    }).catch(()=> {
        console.log('5')
    })
    console.log('6')
    let async0 = async function async1() {
        console.log('7')
        await async2()
        console.log('8')
    }
    async function async2 (){
        console.log('9')
    }
    async0()
</script>

那我们现在根据已知的结论来理一下上面的代码

  1. 首先执行第一行同步代码,{{ 输出 1 }}
  2. 第二行是定时器,属于宏任务,放到宏任务队列,稍后执行
  3. 第五行遇到new Promise先执行,{{ 输出1 3 }}, 此处执行了resolve,说明之后需要执行then中得代码,Promise.then属于微任务,先放到微任务队列
  4. 第十三行属于同步代码,直接执行 {{ 输出 1 3 6 }}
  5. 第十四行到二十一行是定义了两个异步函数
  6. 第二十二行执行了async0,跳到第十四行 {{ 输出 1 3 6 7 }}
  7. 紧接着执行async2函数,{{ 输出 1 3 6 7 9 }}
  8. await之后的第十七行代码放到微任务队列
  9. 主线程任务执行完,现在开始处理微任务队列的任务,Promise.then在微任务队列,第十七行代码也在微任务队列 {{ 输出 1 3 6 7 9 4 8 }}
  10. 微任务队列执行完之后,开始执行宏任务队列的任务, 定时器再宏任务队列中,{{ 输出 1 3 6 7 9 4 8 2 }}

所以最终输出的结果是 1 3 6 7 9 4 8 2

文章有不足的地方还请各位大佬多多指教,本文中没有介绍promise与async/await之间的关系,之后会出一篇文章来详细介绍。