Promise规范及应用(0327)

336 阅读4分钟

参考:www.jianshu.com/p/8a367df8e…

Promise 核心知识点

描述promise框架 - 规范

    1. promise有哪些状态?pendingfulfilledrejected
    1. new Promise 执行器executor(),执行器参数是? - resolvereject
    1. promise的默认状态是?promise状态的流转? - 默认pending pending-->fulfilled pending-->rejected
    1. promise,value保存成功状态的枚举?- undefined thenable promise
    1. promise,失败状态值?- reason保存失败 描述promise接口
    1. promise一定会有then,then接收来源? - 两个回调onFulfilled(value) + onRejected(reason)

executor 与三个状态

  • new Promise 时,需要传递一个 executor 执行器函数,在构造函数中,执行器函数立刻执行
  • executor 执行函数接受两个参数,分别是 resolvereject
  • Promise 只能从 pendingrejected, 或者从 pendingfulfilled
  • Promise 的状态一旦确认,状态就凝固了,不在改变

then 方法

  • 所有的 Promise 都有 then 方法,then 接收两个参数,分别是 Promise 成功的回调 onFulfilled,和失败的回调 onRejected
  • 如果调用 then 时,Promise 已经成功,则执行 onFulfilled,并将 Promise 的值作为参数传递进去;如果 Promise 已经失败,那么执行 onRejected,并将 Promise 失败的原因作为参数传递进去;如果 Promise 的状态是 pending,需要将 onFulfilledonRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行(观察者模式)
  • then 的参数 onFulfilledonRejected 可以不传,Promise 可以进行值穿透。

链式调用并处理 then 返回值

  • Promise 可以 then 多次,Promisethen 方法返回一个新的 Promise
  • 如果 then 返回的是一个正常值,那么就会把这个结果(value)作为参数,传递给下一个 then 的成功的回调(onFulfilled
  • 如果 then 中抛出了异常,那么就会把这个异常(reason)作为参数,传递给下一个 then 的失败的回调(onRejected)
  • 如果 then 返回的是一个 promise 或者其他 thenable 对象,那么需要等这个 promise 执行完撑,promise 如果成功,就走下一个 then 的成功回调;如果失败,就走下一个 then 的失败回调。

手写promise - 同步版本

//    pending -> resolve方法 -> fulfilled
//      pending -> reject方法 -> rejected

// 三个状态:PENDING FULFILLED REJECTED

const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'

class Promise { //类
    constructor(executor){ //构造
        this.status = PENDING
        this.value = undefined
        this.reason = undefined

        let resolve = value =>{
            if(this.status === PENDING){
                this.status = FULFILLED
                this.value =value
            }
         }

        let reject = reason =>{
            if(this.status === PENDING){
                this.status = REJECTED
                this.reason =reason
            }
        }

        try{
        executor(resolve,reject)  //executor 接受上面的两个resolve和reject函数去执行你写入的resolve或reject方法
        }catch(error){
        reject(error)
        }
     }

    then(onFulfiled,onRejected) { // then 接收你写入的callback函数,将你改写的this.value或者this.reason返回出去
        if(this.status === FULFILLED){
            onFulfiled(this.value)
        }

        if(this.status === REJECTED){
            onRejected(this.reason)
        }
    }
}

const promise = new Promise((resolve,reject)=>{
resolve('successs')
// reject('failed')
}).then(
data=>{console.log('data---->',data)},
err=>{console.log('err---->',err)}
)

promise --异步版本


const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'

class MyPromise {
  constructor(executor) {
    this.status = PENDING;
    this.value = undefined;     // 用于保存 resolve 的值
    this.reason = undefined;    // 用于保存 reject 的值
    this.resolvedQueues = [];   // 用于保存 then 的成功回调数组
    this.rejectedQueues = [];   // 用于保存 then 的失败回调数组

    let resolve = value => {
      // 同时遍历执行 成功回调数组中的函数,将 value 传入
      if (this.status == PENDING) {
        this.value = value;
        this.status = FULFILLED;
        this.resolvedQueues.forEach(fn => fn())
      }
    }

    let reject = reason => {
      // 同时遍历执行 失败回调数组中的函数,将 reason 传入
      if (this.status == PENDING) {
        this.reason = reason;
        this.status = REJECTED;
        this.rejectedQueues.forEach(fn => fn())
      }
    }

    try {
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }

  then(onFulfilled, onRejected) {
     // 定义onFulfilled ,onRejected两参数,是因为防止在p1.then()未传入参数报错
    onFulfilled =
      typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected =
      typeof onRejected === 'function' ? onRejected : reason => { throw reason }

    if (this.status === FULFILLED) {
      onFulfilled(this.value)
    }
    
    if (this.status === REJECTED) {
      onRejected(this.reason)
    }
    
    if (this.status === PENDING) {
      this.resolvedQueues.push(()=>{
          onFulfilled(this.value)
      })
      this.rejectedQueues.push(()=>{
          onRejected(this.reason)
      })
    }
    
    return this;
  }
}

let p1 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功了');
  }, 1000);
})

 p1.then((res) => {console.log('结果:',res)})
// p1.then().then((res) => { console.log('结果:',res)})

解释下在异步中为什么要用到resolvedQueues和rejectedQueues这两个数组

执行步骤:

  • 第一步:new MyPromiseh后执行constructor函数,传入的executor就是我们写的
(resolve, reject) => { setTimeout(()=>{ resolve('成功了'); },1000)
  • 第二步:在try{executor(resolve, reject)}执行中,因为executor里面是个setTimeout函数 ,resolve被包裹在里面并没用立即执行,所以执行到then函数时,this.status并没有改变,还是pending状态,then就会将你写入的函数push到数组里
(res) => { console.log('结果:',res); } // 你写入的函数
  • 第三步: 当setTimeOut到时间后开始执行了,这时候触发了resolve函数将this.statu改成FULFILLED状态,将this.value改成成功了,这时候遍历resolvedQueues数组里的各函数,执行之前存入的函数
fn() 
等同于 
(this.value) => { console.log('结果:',this.value) } //this.value === '成功了'