Promise终极技巧——面试必备

566 阅读3分钟

“种一棵树的最好时间是十年前,其次是现在” ————致迷茫中的少年

前情提要

想要解决绝大多数Promise相关的面试题首先你得知道下面几个知识点

  • 1、JavaScript的运行模式
  • 2、EventLoop事件循环和事件队列
  • 3、宏任务和微任务
  • 4、async和await

知识点概述

具体知识点大家可以看一下其他大佬的文章,掘金里有很多都说的都非常好

Js的运行模式:

简言之,记住浏览器是多线程的但js的执行环境是单线程的,就像是一条流水线,按照顺序依次的执行相关任务

EventLoop事件循环和消息队列

  • 1、执行栈中的同步任务进入主线程,异步任务进入Event Table并注册函数再放进EventQueue(消息队列:存放异步任务的地方)
  • 2、主线程内的任务执行完毕后,会去EventQueue读取对应的函数,进入主线程执行。
  • 3、再重复步骤1,如此往复循环

宏任务和微任务

  • 宏任务:

      script标签
      setTimeout
      setInterval
      setImmediate
      ...
    
  • 微任务

    原生Promise(有些实现的promise将then方法放到了宏任务中)
    process.nextTick
    MutationObserver 
    

async和await

  • async 返回的是一个promise对象
  • await 如果产出的是一个promise 会调用这个promise.then方法,await会阻塞后面代码的执行

解题技巧

记住下面的顺序

1.从上往下执行代码

2.同步任务直接执行,遇到异步任务将宏任务放进宏任务队列微任务放到微任务队列

3.当同步任务执行完毕后,先将微任务放入主线程执行

4.最后将宏任务放入主线程执行

注意:

1.await 会阻塞后面代码的执行,做题时await后面的代码可以看做是一个微任务放入微任务队列

2.Promise状态为padding时候不会执行.then()或.catch()方法

面试题

//请写出输出内容
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

注意: 队列是先进先出

解析:
1.代码由上而下执行,首先执行同步代码输出“script start”
2.遇到宏任务setTimeout()放入宏任务队列
3.执行async1(),输出“async1 start”
4.执行await async2()并将后面的代码阻塞,可以看做是放入微任务队列
5.输出“async2”
6.async()执行完成后跳出,继续执行执行栈中的同步任务 
7.执行new Promise()中的代码,输出“promise1”
8.执行resolve()后,Promise的状态变为padding
9.遇到.then()方法,放入微任务队列等待执行
10.执行主线程中最后一个同步任务 输出“script end”
11.将微任务队列中的任务放到主线程执行,先输出“async1 end”
12.主线程中的任务执行完后,再去微任务队列看还有一个.then(),把它移入主线程执行,输出“promise2”
13.主线程任务执行完后再去微任务队列,微任务队列没有任务了,再去宏任务队列执行setTimeout(),输出“setTimeout

第一次写,写这个也花了挺久的时间,有错误的话望大佬指点一下