JavaScript — 事件循环 eventloop

前提梳理

  1. eventloop机制是C++写的,不属于JS。JS是个单线程的语言,来了任务就执行。
  2. eventloop机制在nodejs和chrome浏览器中是不同的。下面我们先梳理nodejs,再讲chrome

Node.js的eventloop

概念图

timers  --->   poll   --->  check
  ↑      在poll阶段停留等待    |
  _________________________
  

当执行一个异步任务发生了什么(理想情况)

  • 普通异步任务

    setTimeout(fn,1000)
    1. JS把setTimeout放在timers阶段的一个数组里,并记录下1000ms
`[{event:fn,time:1000ms}]`
2. JS就不管setTimeout这个任务了,继续去执行JS同步代码
3. 在poll阶段等待1000ms,时间到后到timers阶段执行fn
  • 普通异步任务+setImmdiate

    setTimeout(fn1,1000)
    setImmidiate(fn2)
    1. JS把setTimeout放在timers阶段的一个数组里,并记录下时长1000ms
    2. JS就不管setTimeout这个任务了,继续去执行JS同步代码
    3. 在poll阶段等待,这时候发现setImmideate任务来了,不再等待,跳到check阶段
    4. check阶段有个数组,里边存放了fn2. 带着fn2跳转到timers执行
    5. 执行后发现1000ms还是没到,于是回到poll阶段等待,到了1000ms后再经过check阶段跳转到timers,执行fn

奇怪现象

相信你注意到了上个板块中的“理想情况”四个字。
什么叫理想情况?那就是我们假定eventloop的启动要比js的启动更快。

//test.js
setTimeout(()=>{ console.log('fn1') },1000)
setImmidiate(()=>{ console.log('fn2') })

$ node test.js 
//输出:fn1 fn2
$ node test.js
//输出:fn2 fn1

你会发现,同样的代码居然产生了不一样的结论

所以说,eventloop和js代码,谁启动的更快就决定了执行的顺序!

  • 假设eventloop更快:那么timers阶段,数组里并没有存入setTimout,直接进入poll阶段等待,这时候js才执行。那eventloop先执行fn2,在下一轮执行fn1
  • 假设js执行更快:那么timers阶段,数组里就已经存在了setTimeout,那么久先执行fn2,再执行fn2

复杂题目

const fn = ()=>{
    setImmidiate(()=>{
      console.log('a')
      setTimeout(()=>{
         console.log('b')
     },0)
    })
    setTimeout(()={
     console.log('c')
     setImmidiate(()=>{
            console.log('d')
        })
    },0)
}
fn()

输出:a c b d

Chrome的eventloop

宏任务和微任务

  1. 宏任务:一会儿就做的异步任务

    • setTimeout 等
  2. 微任务:马上就做的异步任务

    • Promise.then 等

运行机制

  1. 规则

    • 同时只能执行一个异步任务
    • 每一轮事件循环只会执行一个宏任务,而可以执行多个微任务。
    • 首先扫描宏任务队列,如果发现待执行的宏任务,则从队列中取出,执行。
    • 若宏任务队列为空(或者执行完一个宏任务后),扫描微任务队列,执行所有微任务,然后进入下一个时间循环
  2. 实例

    setTimeout(() => console.log(4)) 
    new Promise(resolve => {  
       resolve() 
       console.log(1) 
    }).then(() => { 
       console.log(3) 
    }) 
    console.log(2)

    输出: 1 2 3(微任务) 4(宏任务)

进阶题目

async function fn1(){
    console.log(1)
    await fn2()
    console.log(2)
}
async function fn2(){
    console.log(3)
}
fn1()

new Promise(function(resolve){
    console.log(4)
    resolve()
}).then(()=>{
    console.log(5)}
)

输出:1 3 4 2 5

tips:

  • await 展开

    await fn2(); console.log(2)
    //可以合并为 
    fn2().then(()=>{ console.log(2) })

你可能感兴趣的:(javascript,eventloop)