EventLoop,消息队列,宏任务与微任务

一、js为什么是单线程?

js是单线程语言,因为它的主要用途是与用户交互及操作dom,如果多线程的话,一个线程在一个dom节点添加内容,另一个线程删除了这个节点,浏览器不知道以哪个线程为准。js单线程是指浏览器中负责解释和执行js代码的只有一个线程->js引擎线程。浏览器是多线程的有:js引擎线程、事件触发线程、定时触发

二、EventLoop

js单线程意味着js会按照事件顺序执行,若其中某一个事件耗时很久,后面的事件会阻塞,但是我们发现js中定时器,异步请求并不会阻塞后续事件执行,这是为什么呢?

其实,当有计时器、网络请求等异步事件时,js会把它们放到WebAPI中,WebAPI是浏览器提供的线程,然后js会执行后面的其他事件,WebAPI中的异步事件结束后,会把事件的回调函数放到任务队列中去维护,js会在适当的时间去任务队列取出回调函数执行

消息队列类似队列的数据结构,遵循先入先出规则,用于存储消息

JS有执行栈和任务队列,同步任务依次进入执行栈,异步任务会放入任务队列,执行栈中任务结束后会读取任务队列,对应的异步任务结束等待状态进入执行栈开始执行;这个运行机制就是事件循环,自己理解的运行流程图如下:

js执行流程.png

三、宏任务与微任务

宏任务和微任务是异步编程的两种任务

宏任务包括:script(外层同步代码), setTimeout, setInterval, setImmediate, I/O, UI rendering;

微任务包括: Promises, Object.observe, MutationObserver

涉及到此就不得不提经常面试问到的宏任务与微任务的执行顺序

一轮事件循环首先执行宏任务=>执行所有微任务=>UI render=>下一轮事件循环


宏任务与微任务执行顺序.png
console.log(1)
setTimeout(function timer1 () { 
  console.log(2)
}, 1800)
new Promise((resolve, reject)=>{
  console.log(3)
  resolve(123)
}).then(res=>{
  console.log(4)
})
console.log(5)
//打印结果:1 3 5 4 2
//整个代码片段是一个宏任务,setTimeout是一个新的宏任务,要等到本轮微任务结束才开启




console.log(1)
setTimeout(function timer1 () { 
  console.log(2)
}, 1800)
new Promise((resolve, reject)=>{
  console.log(3)
  setTimeout(function timer1 () { 
    console.log(4)
    resolve(123)
  }, 1800)
}).then(res=>{
  console.log(5)
})
console.log(6)
// 打印结果:1 3 6 2 4 5
// Promise中的setTimeout会放到WebAPI中,因为第一个setTimeout先放进去的定时也是1800,所以第一个先执行打印2

console.log(1)
setTimeout(function timer1 () { 
  console.log(2)
}, 1800)
new Promise((resolve, reject)=>{
  console.log(3)
  setTimeout(function timer1 () { 
    console.log(4)
    resolve(123)
  }, 1700)
}).then(res=>{
  console.log(5)
})
console.log(6)
// 打印结果:1 3 6 4 5 2
// Promise中的setTimeout会放到WebAPI中,因为第一个setTimeout先放进去的定时比第二个时间长,所以先走第二个,接着会把对应的微任务走完,接着才会走剩下的setTimeout中任务

你可能感兴趣的:(EventLoop,消息队列,宏任务与微任务)