JavaScript 事件循环

为什么有事件循环?

js单线程,多任务会排队,等待上一个任务执行完毕,如果某个任务执行时间很长,会造成阻塞,因此,JS引入了事件循环机制


事件循环是啥

JS单线程任务分为:同步任务、异步任务

  • 同步任务:在主线程中排队执行,前一个任务执行完毕,再执行下一个任务
  • 异步任务:不进入主线程,异步任务有结果后,把回调函数放到任务队列上,等主线程空闲时执行

在这里插入图片描述
主线程不断在任务队列中读取事件,叫做事件循环


Node中的事件循环

Node基于JavaScript,运行在单个线程中,也就是说,是同步的。然而,输入输出(I/O)和其他原生API是异步运行的,有单独的线程。Node通过事件循环管理这种时序中断。

假如你到熟食店买午餐,排队下单,拿到一个订单号。你坐下来等待,读读报纸、刷刷微博。与此同时,你的订单进入另一个队列,等待熟食店员工处理。但是,午餐并不一定总是按照下单的顺序完成,有些订单可能需要烘烤,耗时长一些。熟食店员工接到订单,把准备好的食材放入烤箱,按下计时器便去做其他任务了。

计时器铃响后,熟食店员工迅速放下手中的任务,从烤箱中取出你的午餐。你听到叫号后,起身取走午餐。如果同时处理多个耗时的午餐食材,熟食店员工会为每个食材按下一个计时器,按照计时器响铃的顺序依次处理

所有Node进程都安装熟食店处理订单的模式排队:先收到的订单先发给熟食店员工(线程)。然而,某些操作,例如I/O,就像需要额外花时间烘烤的午餐订单一样,不要求熟食店员工停下手中的工作等待烘烤结束。烘烤计时器就像Node事件循序中的消息,对请求的操作触发最后的活动


异步任务中的两种任务

在这里插入图片描述

宏任务(macroTask || Task):script(外层同步代码)、setInterval、SetTimeout、setImmediate(IE特有)、I/O
微任务(microTask || Job): 当前task执行结束后立即执行的任务。Promise.then/catch/finally、MutationObserver回调(H5特性,用于监听节点变化)

单个宏任务执行完后,检查微任务队列是否为空,如果不为空,按先入先出,全部执行完微任务后,在执行下一个宏任务

console.log(1);

// 异步,不能设置延迟时间,只能执行一次
setImmediate(function () {
    console.log('2');
});

console.log(3);

//  1 -> 3 -> 2

为什么要有微任务?

事件队列是先进先出的结构,排在前面的优先被主线程读取,如果来了个高优先级的任务,让它去排队就不够人性化了

  • 你去银行柜台办业务,银行的人会问你办什么业务,根据业务不同可能需要填表,然后让你去取号
  • 你要取10万块,这是不需要填表的
  • 柜员办理业务相当于主线程
  1. 你先去取号排队,等待叫号
  2. 轮到你时,发现银行卡不见了,取钱的业务办不了 (宏任务)
  3. 你需要填一份表,然后办理挂失业务,拿到新卡后,才能继续执行取钱任务 (微任务)

如果没有微任务,柜员叫你去填表然后重新排队(显然不合理)


事件循环练习题

async function async1() {
    console.log("async1 start")
    await async2()
    console.log("async1 end")
}
 
async function async2(){
    console.log("async2")
}
 
console.log("script start")
 
setTimeout(function(){
    console.log("setTimeout")
}, 0)
 
async1()
 
new Promise(function(resolve){
    console.log("promise1")
    resolve()
}).then(function(){
    console.log("promise2")
})
 
console.log("script end")
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
console.log("start");
setTimeout(() => {
    console.log("children2")
    Promise.resolve().then(() =>{
        console.log("children3")
    })
}, 0)
 
new Promise(function(resolve, reject){
    console.log("children4")
    setTimeout(function(){
        console.log("children5")
        resolve("children6")
    }, 0)
}).then(res =>{
    console.log("children7")
    setTimeout(() =>{
        console.log(res)
    }, 0)
})
start
children4
children2
children3
children5
children7
children6
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值