解读前端面试 EventLoop事件循环机制

前言

EventLoop 是计算机系统的一种运行机制。JavaScript语言就采用这种机制,它是一种单线程语言,所有任务都在一个线程上完成,一旦遇到大量任务或者遇到一个耗时的任务,网页就会出现"假死",因为JavaScript停不下来,也就无法响应用户的行为。为了解决这个问题JS中出现了同步任务和异步任务。

简单来说:eventloop事件循环机制 是指浏览器或Node运行环境里解决javaScript单线程运行时不会阻塞的一种机制,也是我们经常在项目里使用异步 promise / async await 的原因。

什么是 同步任务 / 异步任务

Javascript单线程任务被分为 同步任务(synchronous) 和 异步任务(asynchronous)。同步任务 会在调用栈中按照顺序等待主线程依次执行。异步任务 会在异步任务有了结果后,将注册的回调函数放入任务队列中等待主线程空闲的时候(调用栈被清空),被读取到栈内等待主线程的执行。

异步任务分为 宏任务微任务
微任务和宏任务它们都属于一个队列,主要区别在于他们的执行顺序 ( 同步任务 -> 微任务 -> 宏任务)

异步任务的运行机制

1.所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
2.主线程之外,还存在一个"任务队列"(task queue)。遇到异步任务,就在"任务队列"之中放置一个异步事件。
3.一旦"执行栈"中的所有同步任务执行完毕,就会读取"任务队列"中的事件对应的异步任务,进入执行栈,开始执行。
4.主线程不断重复上面的第三步。

异步任务流程图

宏任务和微任务

宏任务(macrotask):
异步Ajax请求
setTimeout 、setInterval、setImmediate、requestAnimationframe
其他宏任务

微任务(microtask):
Promise.then、Promise.catch、Promise.finally
process.nextTick
其他微任务

宏任务

method浏览器Node
setTimeout
setInterval
setImmediate
requestAnimationframe

微任务

method浏览器Node
process.nextTick
MutationObserver
Promise.then、Promise.catch、Promise.finally

练习

setTimeout(() => {  // ①                  
	console.log("1-1");
	Promise.resolve().then(() => {
		console.log("2-1");
	});
});
console.log("1-2"); 
Promise.resolve().then(() => {
    console.log("1-3");
	setTimeout(() => {  // ②
		console.log("3-1");
	});
});

// 运行结果
 // 1-2    ①整体被放入宏任务队列中,执行同步任务log 打印 1-2
 // 1-3    .then同步任务 打印 1-3 ,② 放到宏任务队列中,同步任务执行结束,执行栈清空,读取执行异步任务
 // 1-1	   执行①中的同步任务,打印 1-1    
 // 2-1    .then同步任务 打印 2-1
 // 3-1    执行②中的同步任务 打印 3-1
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('Promise')
    resolve()
}).then(function(){
    console.log('Promise2')
})

console.log('script end')

// 运行结果:
// script start  打印log值
// async1 start  执行async1函数,打印log值 
// async2        await 执行async2 打印log值 await后面的代码被压入microtask队列。当主线程执行完毕,取出这个回调,执行。 所以先不打印 async1 end,去先执行async函数之后的代码。
// Promise       new Promise回调函数是同步执行的, 创建 promise 对象后立即执行,打印log
// script end    同步代码log,到此主线程执行完毕。
// async1 end    await后的代码第三步时被放入了回调,回调被执行
// Promise2      执行 .then回调(微任务队列)
// setTimeout    执行 setTimeout(宏任务队列)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

404not~found

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值