JavaScript — 事件循环 eventloop

前提梳理

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

Node.js的eventloop

概念图

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

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

  • 普通异步任务node

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

    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. 宏任务:一下子就作的异步任务async

    • setTimeout 等
  2. 微任务:立刻就作的异步任务ide

    • Promise.then 等
  3. 实例oop

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

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

进阶题目

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) })
相关文章
相关标签/搜索