Promise面试题你就这么答!干货满满

113 阅读5分钟

这篇文章根据A+规范和Promise官网描述实现的Promise,看完对Promise的理解增加90%

手写原生Promise

Promise的特性无非就这几种

  1. Promise的状态是不可逆的
  2. Promise通过调用resolvereject方法修改当前Promise的状态
  3. then方法是异步执行的,是微任务,通过传入回调函数得到成功或失败后的结果
  4. then方法不传入回调函数会有穿透效果,结果会传递到下一个then方法
  5. then方法的返回值是立即成功的Promise对象,除非then方法内的回调函数发生报错
  6. then方法是可以链式调用的,每个then得到的结果就是上一个then方法的返回值
  7. catch方法在Promise状态为失败时执行,传入回调函数得到失败的结果
  8. catch方法返回值是立即成功的Promise对象,除非catch方法内的回调函数发生报错
  9. finally方法无论当前Promise状态成功还是失败都会执行,并且返回值为与当前Promise状态一致的Promise对象
  10. Promise.all()方法将多个多个Promise实例,包装成一个新的Promise实例,该方法接受一个由Promise对象组成的数组作为参数(Promise.all()方法的参数可以不是数组,但必须具有Iterator接口,且返回的每个成员都是Promise实例),注意参数中只要有一个实例触发catch方法,都会触发Promise.all()方法返回的新的实例的catch方法,如果参数中的某个实例本身调用了catch方法,将不会触发Promise.all()方法返回的新实例的catch方法
  11. Promise.race()方法的参数与Promise.all方法一样,参数中的实例只要有一个率先改变状态就会将该实例的状态传给Promise.race()方法,并将返回值作为Promise.race()方法产生的Promise实例的返回值
  12. Promise.resolve()方法返回一个立即成功的Promise对象,并且传入的参数分3种情况:Promise自己的实例对象 满足A+规范的实例对象 传入值 三种情况的结果都不一样
  13. Promise.reject()方法相对简单,返回值是立即失败的Promise对象,传入的参数是什么返回的Promise对象的值就是什么

状态不可逆

在我们调用resolve方法或者reject方法时,只有当Promise的状态为pending时才可以修改为成功或者失败,先调用了resolve后调用reject,那么reject方法是没有效果的,比如:

new Promise((resolve,reject) => {
    resolve('成功')
    reject('失败')
})

这段代码最后的结果返回的是状态为fulfilled值为成功Promise对象,reject方法执行了但是内部不会做任何行为

异步调用resolve和reject方法

我们使用Promise更多情况是发送AJAX请求,AJAX是一个异步任务,所以我们在发送请求成功后调用resolve方法时为什么会等待异步任务完成后,还能获取到数据呢? 这里使用定时器模拟请求,比如:

new Promise((resolve,reject) => {
    setTimeout(() => {
      resolve('成功')
    })
})

因为我们传入的函数是同步执行的,所以修改不到状态,那么Promise内部通过把回调函数中所有的参数保存到对象中推到一个队列里面,当异步任务完成时修改了状态,就从队列中把所需的参数拿出来执行

then方法

then方法最关键的地方就在于他返回的是一个新的Promise对象,才足以实现这么多功能

then内的回调函数是微任务

then方法中是异步执行的,有3种方法,首先判断你所处的是什么环境,使用不同的方法

  1. 首先判断有没有process对象,如果有则调用precess.nextTick方法实现微任务
  2. 判断有没有MutationObserver这个构造函数,如果有就使用MutationObserver实现微任务
  3. 都没有那只能使用setTimeout来实现异步,setTimeout内的回调会添加到延时队列,执行优先级会低于微任务

then方法的穿透效果

执行then时会去判断传入的回调函数是否为function类型,如果不为function那么会返回一个新的Promise对象,调用resolve方法把当前回调的结果传进去,那么下一个then方法就可以接收到上一个then的结果了

链式调用

then方法返回的是一个Promise对象,那么我们就可以调用他的原型方法了,返回Promise对象是链式调用的关键

resolve静态方法

我们传入的参数分三种情况

  1. Promise实例化的对象

返回值为Promise对象,调用resolve方法,把传入这个对象,作为参数传入,调用then方法时得到的就是传入的Promise对象,举个例子:

const p = new Promise((resolve,reject) => {
    resolve('成功')
})

console.log(Promise.resolve(p) === p) // true
  1. 传入一个满足A+规范的对象

不管你是函数,构造函数,还是对象,只要你满足了then方法就是满足了A+规范,Promise内容判断你符合了A+规范时,会调用你自身的then方法,返回的结果取决于then方法

  1. 传入普通值

返回的就是一个成功状态的Promise,结果就为传入的参数

await async 跟 Promise 的区别

  1. 都是用来处理异步代码请求的
  2. Promise是es6出的,async await是es7出的
  3. async await是基于Promise实现的,都是非阻塞性的
  4. Promise是通过then()和catch()处理结果和捕获异常,可以链式调用,还是会出现回调地狱的情况
  5. async await是通过try catch捕获异常
  6. 最大的区别就是async await代码看起来跟同步一样,当遇到await就会立即返回结果