关于Event Loop机制的解析

首先我们要知道JS是单线程的,而对于游览器进程来说,不仅仅有处理JS的线程,还有其他的线程,像渲染页面的GUI线程,维护事件队列的事件触发线程,处理setTimeout,setInterval的定时器触发线程,处理异步HTTP请求的异步HTTP触发线程

例如setTimeout定时任务就是在定时器触发线程中进行的,当定时任务完成后会通知事件触发线程,把相应的回调函数放到事件队列中去,AJAX和Fetch等同理

了解完每个线程对应的任务之后,接下来我们再来正式介绍下Event Loop(事件循环机制)

首先我们知道JS分为同步任务和异步任务,另外setTimeout和setInterval是同步任务,关于其中的回调函数才是异步任务

JS线程有个执行栈,首先全部的同步的代码会在执行栈中执行,当遇到了setTimeout这样的API的时候,就会交给定时器触发线程执行,然后时间到了就会添加到事件队列中去,当执行栈的同步代码执行完成之后,就会检查事件队列中是否有剩余的回调函数,如果有就拿到执行栈中执行,JS就是无限重复这个步骤,所以被称为事件循环

下面我们看一个例子

console.log(1111)

setTimeout(() => {
  console.log(3333)
  setTimeout(() => {
    console.log(5555)
  })
})

setTimeout(() => {
  console.log(4444)
})

console.log(2222)

// 结果: 1111 -> 2222 -> 3333 -> 4444 -> 5555

从头开始,首先打印1111,然后遇到setTimeout,交给定时器触发线程执行,完成后将相应的回调函数添加到事件队列中去,下面又遇到setTimeout时一样处理,这时事件队列中已经有两个回调函数了,再然后打印2222,这时候执行栈为空了,然后去查看事件队列,首先会把第一个回调函数添加到执行栈中去,打印3333,然后第一个回调函数中又有setTimeout又重复刚才的步骤,当第一个回调函数执行完之后,执行栈为空,又去查看事件队列中的函数,接下来就是重复刚才的步骤,然后打印4444,5555

然后关于Promise的出现,又把JS划分成微任务和宏任务,我们可以将每次执行栈执行的代码当做是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)

下面我们再看一个例子

new Promise((resolve, reject) => {
  console.log(1111)
  resolve(2222)
}).then(res => {
  console.log(res)
})

setTimeout(() => {
  console.log(3333)
})

// 结果: 1111 -> 2222 -> 3333

首先执行new Primise打印2222,遇到then之后把then中的回调函数加入微任务队列,再执行setTimeout,按照之前的步骤,放到事件队列中去,当执行栈为空时,首先会执行微任务队列中的函数,执行完成之后又会执行宏任务(如果没有就从事件队列中拿),执行完之后再执行微任务,依次循环

不过关于then中的回调函数的时机应该是resolve执行之后(个人猜测)

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(2222)
  })
}).then(res => {
  console.log(res)
})

new Promise((resolve, reject) => {
  resolve(1111)
}).then(res => {
  console.log(res)
})

setTimeout(() => {
  console.log(3333)
})

// 结果: 1111 -> 2222 -> 3333

参考:「前端进阶」从多线程到Event Loop全面梳理

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值