五分钟面试题—— EventLoop 事件循环判断(附字节真题)

2,546 阅读4分钟

前言

兄弟们周三好,最近在做年中总结的时候,发现自己更新文章的频率跟不上了,在社区中想要更多的文章曝光需要,更加频繁而且高效的输出优质的文章,而且整个互联网大环境依然不好,我们需要把精力更多的放在自我成长上面,而不是过多的无效加班上,所以需要我们更多地总结和学习新的内容,然后产出脑图或者MD文档。最近互联网大厂开启第二轮裁员潮,不知道身边的小伙伴有没有遭遇到被裁的风险,anyway,我们需要更多地关注个人能力的成长上,这样才是合格的打工人,今天我们要来分享字节的真题,对一个事件循环的判断

在看了优弧大大的 科普社区玩法和建议的文章以后,我觉得很有必要提高自己文章的质量和输出更多自己总结归纳的内容。

背景&概念

首先浏览器是通过线程去执行任务的,一个个函数可以理解成一个个任务。 我们把所有任务代码按照顺序写进主线程里,等线程执行时,这些任务会按照顺序在线程中依次被执行;等所有任务执行完成之后,线程会自动退出。总体来说是简单的按照顺序执行。

但并不是所有的任务都是在执行之前统一安排好的,大部分情况下,新的任务是在线程运行过程中产生的。所以上面简单的过程是不存在的

想要在执行的过程中,能接受新的任务,然后就需要采用事件循环的机制来实现了。

image.png

事件循环(EventLoop),我理解事件循环的概念,首先是运行栈(同步代码),任务队列(异步代码),事件循环其实就是不断检测 任务队列中是否有内容需要执行的这样的过程。整个js这种运行机制又称为Event Loop(事件循环)

整体过程

  1. 函数入栈,当Stack中执行到异步任务的时候,就将他丢给WebAPIS,接着执行同步任务,直到Stack为空;
  2. 此期间WebAPIS 完成这个事件,把回调函数放入队列中等待执行(微任务放到微任务队列,宏任务放到宏任务队列)
  3. 执行栈为空时,Event Loop把微任务队列执行清空;
  4. 微任务队列清空后,进入宏任务队列,取队列的第一项任务放入Stack(栈)中执行,回到第1步。

image.png

微任务和宏任务

  • 微任务 Promise then,MutationObserver
  • 宏任务 setInterval,setTimeout,setImmediate(ie),MessageChannel

例子🌰

console.log(1); 
console.log(2);
Promise.resolve().then(function() {
    console.log(3);
})
setTimeout(function () { 
    console.log('setTimeout1'); 
    Promise.resolve().then(function () { 
        console.log('promise'); 
    }); 
});
setTimeout(function () { 
    console.log('setTimeout2'); 
});
// 1 2 3 setTimeout1 promise setTimeout2

解释过程

  1. 执行当前的栈
  2. 执行微任务 Promise then
  3. 将宏任务的第一项推到栈中执行 如果嵌套了 Promise的微任务 微任务就加入微任务队列
  4. 执行微任务
  5. 将宏任务的第二项推到栈中执行,如此循环

字节真题

async function async1() {
  console.log('a');
  await async2();
  console.log('b');
}

async function async2() {
  console.log('c')
}

console.log('d')
async1();

setTimeout(()=> {
  console.log('e')
},0)

new Promise((resolve, reject) => {
  console.log('f')
  resolve()
}).then(()=> {
  console.log('g')
})

思路

我们在解题的过程中不妨把思路写上去然后

  1. 执行当前的栈 我们可以看到 打印 d, 然后执行 async1 函数()
  2. 执行 async1 函数 它是一个微任务,所以先 打印 a, 再执行 async2 函数 打印 c,然后将后面剩余的打印推入 微任务的队列中
  3. 执行 setTimeout 宏任务,我们将它推入 宏任务的队列中
  4. 执行 new Promise 回调函数 打印 f,将 then 回调函数推入 微任务 队列
  5. 至此函数执行完毕,函数任务各自都进入该去的任务队列
  6. 先清空微任务队列中函数,按照先进先出的顺序执行,打印 b, 然后打印 g
  7. 最后清空宏任务队列中的函数,打印 e
  8. 至此一轮的事件循环结束🔚

答案

1. d
2. a
3. c
4. f
5. b
6. g
7. e

小结

这篇文章到这里就结束了,水平有限难免有纰漏,欢迎纠错。最后希望帮忙点点赞,这对我创作是无比的肯定和动力。希望可以帮到你

文章参考

juejin.cn/user/852876…
developer.mozilla.org/zh-CN/docs/…