(滴滴面试)事件循环Event Loop及微任务和宏任务的执行过程详解

678 阅读2分钟
   之前一直在面试,对于一些大厂面试题真的还是很注重原理和基础的,
还有就是数据结构和算法这种,校招的话,这些是很重要的,
前天和滴滴的人面试,问的真心觉得不难,而且也都是现在面试前端很常见的问题,
对于一道事件循环和微任务和宏任务的这道题,之前也是经常被面试到,但是一直没有放在心上,
本以为自己搞懂了,但是真正到了输出代码的时候,还是不清楚。
所有今天就要彻底弄懂事件循环到底是什么,以及他们到底是怎么执行的。

下面的讲述,以前天面试滴滴的那道事件循环题目为例子,进行展开

javaScript代码执行过程

JavaScript本身是一个单线程的任务,虽然在H5中新增了webWorker,支持了多线程任务,
但是他从本质上说还都是单线程任务,他们都是使用js的单线程任务模仿出来的,所以对js的执行过程,
下面还是画个图表示比较清楚:

微任务和宏任务

除了我们简单的同步任务和异步任务之外,我们还有一些宏任务和微任务:

常见的宏任务:setTimeout, setInterval, setImmediate, I/O, UI rendering
常见的微任务:process.nextTick, Promises, Object.observe(废弃), MutationObserver, promise.then

关于promise:
    promise本身是同步的,但是他里面的回调函数是异步的,也就是new Promise()是同步的,但是他们里面的参数resolve()和reject()是异步的任务,
    也就是宏任务队列
    还有就是promise.then()这个方法也是微任务队列中的

执行过程

对于整个js的执行过程,先执行一个宏任务,然后执行宏任务里面所有的微任务,微任务执行完毕,
在开始执行一个宏任务,注意:script是一个宏任务,所以主线程上的任务第一个是宏任务
宏任务队列可以有多个,
微任务队列只有一个

执行分析

滴滴校招面试题目
var p1 = new Promise((resolve, reject) => {
      setTimeout(resolve, 1000, 1);
    })

    setTimeout(() => {
      console.log(2);
    }, 0)

    var p2 = new Promise((resolve, reject) => {
      resolve(3)
      console.log(4)
    })

    p2.then((res) => {
      console.log(res)
    }).then((res) => {
      console.log(res)
    })

    p1.then((res) => {
      console.log(res)
    })

    console.log(5)

    console.log("1")

async和await在浏览器中运行

    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')

执行结果画图如下:

测试二

 async function testSometing() {
      console.log("执行testSometing");
      return "testSometing";
    }

    async function testAsync() {
      console.log("执行testAsync");
      return Promise.resolve("hello async");
    }

    async function test() {
      console.log("test start...");
      const v1 = await testSometing();
      console.log(v1);
      const v2 = await testAsync();
      console.log(v2);
      console.log(v1, v2);
    }

    test();

    var promise = new Promise((resolve) => {
      console.log("promise start..");
      resolve("promise");
    }); 
    promise.then((val) => console.log(val));
    setTimeout(() => { console.log("setTime1") }, 3000);
    console.log("test end...")