Promise 基础解剖(一)

237 阅读5分钟

什么是 Promise?

ES6中新增一个内置的类,Promise是一种承诺/约定模式, 基于这种模式可以有效的处理异步编程,可以解决传统的回调地狱问题

什么是回调地狱,它的缺点又是什么?

  • 回调地狱:在传统实现异步操作,并且是串行的模式下,基本上都是回调函数嵌套回调函数,实现"回调地狱"的问题
  • 弊端:可维护性差、可读性差、可复用性差、代码量大,并且只能在回调函数中处理异常

解决回调地狱的方式有哪些?

  • Promise
  • Promise.all
  • async/await

Promise 的三大概念

  • executor 函数
    • new Promise 的时候会立即执行 executor 函数

    • 在 executor 函数中管理了一个异步编程代码(同步代码也是OK的),此时 Promise 状态是 pending;

    • 在我们异步操作成功或者失败的时候,通过执行 resolve 或者 reject 函数,可以有效的把实例改成成功状态或者失败状态,也就是从 pending 变为 fulfilled(成功)/rejected(失败);

    • 如果代码报错的情况下,也是把状态改为失败;

  • 实例
    • 每一个 Promise 实例都具备[[PromiseState]]和[[PromiseResult]]方法

    • [[PromiseState]] 是 promise 状态:pending、fulfilled/resolve、rejected 三种状态

    • [[PromiseResult]] 是 promise 值:默认是 undefined,一般存储成功的结果或者失败的原因。

  • then(): 用来管控成功或者失败的操作
    • 执行 .then 方法返回一个全新的 promise 实例

    • 实例可以调用 .then(),它会存放两个方法:result 和 reason (都是函数)

      • 当实例的状态修改为 fulfilled 的时候,通知传递的第一个函数(result)执行,result 就是 [[PromiseResult]] 的值

      • 当实例的状态修改为 rejected 的时候,通知传递的第二个函数(reason)执行,reason 就是 [[PromiseResult]] 的值

    • 不论是否基于 THEN 注入了方法,执行 resolve/reject 的时候,修改状态和值是同步的会立即处理

    • 但是,通知对应注入方法执行的这个任务是异步操作的,不会立即处理,只是把它排在等待任务队列中,当其他事情处理完,再次返回去,通知对应注入的方法执行

    • then(onfulfilled, onrejected): 执行 then 方法只是把 onfulfilled/onrejected 函数保存起来了(这个保存的操作是同步的)

    • 但是此时函数还没有执行,当 promise 状态变为成功或者失败的时候,才会去触发执行对应的函数

    • 所以,then 方法是一个异步的微任务

.then() 分为两种情况执行

  • 当前实例的状态已经是成功或者失败,此时创建一个异步的微任务,等待同步业务结束,根据成功还是失败,来决定执行哪个方法
  • 如果此时的状态还是 pending,则直接把方法存储起来即可,没有创建异步的微任务
    • 当执行 resolve/reject 的时候,才会去创建一个异步的微任务,等待同步的结束后根据状态执行基于.then 动态存储的函数

Promise 如何管控异步编程的?

  • new Promise 的时候创建一个 promise 实例,此时在 executor 函数中管理一套异步的代码

  • 后期等异步操作成功或者失败的时候,执行 resolve/reject,以此来控制 promise 实例的状态和结果

  • 根据状态和结果,就可以控制基于 .then 注入的两个方法中的哪一个去执行了

let p1 = new Promise(function (resolve, reject) { 
  setTimeout(function(){
    resolve('OK');
  }, 1000)
});

p1.then(result=>{
  console.log('成功', result)
}, reason=>{
  console.log('失败', reason)
})
});

Promise 实例状态和值的分析

  • 第一种情况:new Promise 出来的实例
    • resolve 和 reject 的执行控制其状态 [[PromiseState]] 以及值 [[PromsieResult]]

    • executor 函数执行失败,控制其状态 [[PromiseState]] 为:rejected 以及值 [[PromsieResult]] 为报错信息

  • 第二种情况:通过执行 then 返回的新实例
    • then 注入的两个方法,不论哪个方法执行,只要执行不报错,新实例的状态就是 fulfilled;只要执行报错,新实例的状态就是 rejected,并且新实例的 [[PromiseResult]] 是执行 then 方法返回的值

    • 如果返回的值是一个新的 promise 实例,则新的 promise 实例最后的成功或者失败,直接决定 then 返回的实例的成功和失败

    • 在 .then 注入方法的时候,如果其中某个方法没有传递,则会顺延到下一个 then 中具备相同状态需要执行的函数上

    • 在多个 THEN 链下,其余的 THEN 方法基本都存放的是成功处理的事情,最后一个 THEN 存放失败的,这样不论是第一次或者其中某一次,导致 promise 实例状态是失败的,都会顺延到最后一个失败的处理函数上进行处理...

then(null, reason=>{...}) 
用 catch(reason=>{...}) 来代替

同时处理多个 Promise 实例的方法

  • Promise.all:等待所有的 promise 实例都成功,整体返回的状态才是成功,只要有一个失败的,整体状态就是失败
  • Promise.race:看多个实例谁先处理完,先处理完成的状态不论是失败还是成功,就是最后整体的状态

Promise 常用的属性有哪些?

Promise 作为对象中的属性

  • Promise.all
  • Promise.race
  • Promise.resolve()
  • Promise.reject()

Promise 作为类的两个内置属性

  • [[PromiseState]] promise 状态
    • pending:准备状态
    • fulfilled(旧版本浏览器)/resolved(新版本浏览器):成功状态(已兑现)
    • rejected:失败状态(已拒绝)
    • 但是一旦状态从 pending 改变为 fulfilled 或者是 rejected, 都无法再次改变其状态
  • [[PromiseResult]] promise 值
    • 默认是 undefined,一般存储成功的结果或者失败的原因

Promise 原型上的方法

  • then
  • catch
  • finally