浅谈promise原理和应用

424 阅读17分钟

promise的介绍

(1) 什么是promise

Promise 对象用于表示一个异步操作的最终完成(或失败)及其结果值。它让你能够把异步操作最终的成功返回值或者失败原因和相应的处理程序关联起来。这样使得异步方法可以像同步方法那样返回值:异步方法并不会立即返回最终的值,而是会返回一个 promise,以便在未来某个时候把值交给使用者,这个官方对primise 的定义。

一个完整的promise 对象,在实例化的过程中,必然会处于以下三种状态中的其中一种状态,而且状态一旦确认,就不能再次更改状态。

  • 待定(pending) :初始状态,既没有被兑现,也没有被拒绝
  • 已兑现(fulfilled) :意味着操作成功完成。
  • 已拒绝(rejected) :意味着操作失败。

同时,promise对象还会有Promise.all(), Promise.resolve, finally(), catch() 等几个静态和实例方法

promises.png

Promise 的基本使用

为什么使用Promise

promise 的出现是为了解决js 异步执行和函数回调地狱的问题。常见的异步操作有以下几种模式:

  • 定时器
  • 接口调用
  • 时间函数

使用定时器可以控制js 的执行顺序,让定时器是在固定时间触发某个回调函数。

function callBlack() {
	console.log("执行完成")
}
console.log("before setTimeout")
setTimeout(callBlack, 1000) // 1秒后调用callBack函数
console.log("after setTimeout")

运行后控制台的输出结果为:

before setTimeout 
after setTimeout 
执行完成 //1秒后打印

回调地狱的代码示例:

setTimeout(function () {
    //第一层
    console.log("1111")
    setTimeout(function () {
        //第二程
        console.log("2222")
        setTimeout(function () {
                //第三层
                console.log("3333")
        }, 1000)
    }, 2000)
}, 3000)

但是,使用setTimeout 进行异步代码变成同步去执行控制,当程序代码量足够大的时候,或者有多个定时器时间相同时,程序就有可能不按我们预想的执行顺序去执行。 这时,使用promise 就能很好的解决代码执行顺序的问题。

function callBlackPro(){
    return '执行完成-'
  }
  const p = new Promise((resolve,reject)=> {
    resolve("before setTimeout")
  }).then(res => {
    console.log(res,11)
    return new Promise((resolve,reject)=>{
      setTimeout(()=>{
      resolve(callBlackPro())  // 调用callBlackPro() 函数
      },1000)
    })
  }).then(res => {
      console.log(res,22)
      return new Promise((resolve,reject)=>{
        resolve("after setTimeout")
      })
  }).then(res=> {
      console.log(res,33)
  })

运行后控制台的输出结果为:

before setTimeout 11
执行完成- 22
after setTimeout 33

promise 的基本使用

Promise 实例化的时候,传入的参数是一个函数,函数中接收两个参数:resolve 和reject。

传入的 resolve 和 reject 本身都是函数。其作用分别为:

  • resolve - 把 Promise 的状态从进行中变为成功状态。
  • reject - 把 Promise 的状态从进行中变为拒绝状态。

Promise的三种状态:

pending :进行中,表示 Promise 还在执行阶段,没有执行完成。

fulfilled:成功状态,表示 Promise 成功执行完成。

rejected:拒绝状态,表示 Promise 执行被拒绝,也就是失败。

Promise 的状态,只可能是其中一种状态,从进行中变为成功或失败状态之后,状态就固定了,不会再发生改变。

const p = new Promise((resolve,reject)=>{
   resolve('123')
  }).then(res=>{
   console.log(res) //打印123
})

Promise 链式调用

模拟一个ajax 接口调用网络请求

  • 第一次返回 a,
  • 修改返回的结果为 aa,作为第二次网络请求返回的结果。
  • 修改结果为 aaa,作为第三次返回结果

这种场景其实就是接口的多层嵌套使用,Promise 可以把多层嵌套按照线性的方式进行书写,非常优雅

const pp = new Promise((resolve, reject) => {
    setTimeout(() => {
       resolve("a")
    }, 1000)
}).then((res) => {
    console.log("res1", res) //1秒后打印 a
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(res + "a")
        }, 1000)
    })
}).then((res) => {
    console.log("res2", res) //2秒后打印 aa
    return new Promise((resolve, reject) => {
        setTimeout(() => {
           resolve(res + "a")
        }, 1000)
    })
}).then((res) => {
    console.log("res3", res) //3秒后打印 aaa
})

运行后控制台的输出结果为:

res1 a
res2 aa
res3 aaa

简写的方式:

const pppp = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("a")
    }, 1000)
}).then((res) => {
  console.log("res1", res)
  return res + "a"
}).then((res) => {
  console.log("res2", res)
  return res + "a"
}).then((res) => {
  console.log("res3", res)
})

Promise 方法使用

  1. all() 方法

Promise.all 方法,提供了并行执行异步操作的能力,并且在所有异步操作完成之后,统一返回所有结果。

all() 方法特点是,需要方法内的所有Promise请求都是成功的,只要有一个不是成功的,就会返回失败的结果。 具体使用如下:

Promise.all([
  new Promise((resolve) => resolve("a")),
  new Promise((resolve) => resolve("b")),
]).then((res) => {
  console.log("all", res) // all [ 'a', 'b' ]
})
  1. race 方法

Promise.race 用法与 all 一样,只是返回结果上不同,它返回的是执行最快的那个 Promise 的结果。

Promise.race([
    new Promise((resolve) =>
      setTimeout(() => {
        resolve("a")
      }, 1000)
    ),
    new Promise((resolve) =>
      setTimeout(() => {
        resolve("b")
      }, 2000)
    ),
  ]).then((res) => {
    console.log("race", res) // 返回 a
  })
  1. Promise.resolve方法 可以调用Promise 的静态resolve方法,resolve方法可以接受普通值或者Promise对象值
function p1() {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("成功")
      }, 200)
    })
  }
  Promise.resolve(100).then((value) => console.log(value)) // 100
  Promise.resolve(p1()).then(value => console.log(value)) // 成功
  1. Promise.allSettled Promise.allSettled() 静态方法将一个 Promise 可迭代对象作为输入,并返回一个单独的 Promise。当所有输入的 Promise 都已敲定时(包括传入空的可迭代对象时),返回的 Promise 将被兑现,并带有描述每个 Promise 结果的对象数组。

和 Promise.all 的区别是:

Promise.allSettled和Promise.all的最大不同:Promise.allSettled永远不会被reject。

const promises = [
    Promise.resolve(100).then(() => 1),
    Promise.resolve(200).then(() => 2),
    Promise.reject(3)
    ]
  
  Promise.allSettled(promises).then(values=>console.log(values))
  // 最终输出: 
  //    [
  //      {status: "fulfilled", value: 1},
  //      {status: "fulfilled", value: 2},
  //      {status: "rejected", value: 3},
  //    ]
  Promise.resolve(p1()).then(value => console.log(value)) // 成功

1.简单实现promise功能

promise 的实现原理,promise是一个类,内部定义一些静态方法实例方法

  1. 执行这个类的时候需要传递一个执行器进去,立即执行这个执行器。
  2. promise有三种状态,成功fulfilled,失败rejected,等待pending。
  3. 状态一旦确认就不可更改
  4. then方法状态是成功,就调用成功的回调函数; 状态是失败就调用失败的回调函数
  5. then方法的成功或者失败的回调函数,都有一个返回值表示成功或失败原因 下面是具体的代码实现:
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
const PENDING = 'pending';

class MyPromise {
    constructor(executor) {
        // 执行器
        executor(this.resolvethis.reject)
    }

    // 状态更开始的时候是等待
    status = PENDING;

    // 保存成功后的返回值
    successData = undefined;
    // 保存失败后的返回值
    failData = undefined;
    resolve = (successData) => {
        // 如果状态不是是等待,阻止程序向下执行
        if (this.status !== PENDINGreturn;
        // 将状态改为成功
        this.status = FULFILLED;
        this.successData = successData;

    };
    reject = (failData) => {
        // 如果状态不是是等待,阻止程序向下执行
        if (this.status !== PENDINGreturn;
        //将状态改为失败
        this.status = REJECTED;
        this.failData = failData;
    };

    then(successCallback, failCallback) {
        // 判断状态
        if (this.status == FULFILLED) {
            successCallback(this.successData)
        } else if (this.status == REJECTED) {
            failCallback(this.failData)
        }
    }
}

// commonjs 模块化导出
module.exports = MyPromise;

实例化调用:

// index.js

// 导入MyPromise
const MyPromise = require("./myPromise");

const promise = new MyPromise((resolve, reject) => {
    resolve("成功")
  //  reject("失败")
});

promise.then(success => {
    console.log(success)
}, fail => {
    console.log(fail)
})

2. promise 实现异步逻辑

promise 的异步逻辑实现,其实就是在then()方法中,判断当前的promise 是处于pending,fulfilled, rejected 三种状态的哪一种,当还是pending 时,使用一个数组,将成功或者失败的回调存储起来,然后异步结束后 执行resolve 或者reject。


const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
const PENDING = 'pending';

class MyPromise {
    constructor(executor) {
        // 执行器
        executor(this.resolvethis.reject)
    }

    // 状态更开始的时候是等待
    status = PENDING;

    // 保存成功后的返回值
    successData = undefined;

    // 保存失败后的返回值
    failData = undefined;
    // 保存成功的回调
    successCallback = undefined;

    // 保存失败的回调
    failCallback = undefined;
    resolve = (successData) => {
        // 如果状态不是是等待,阻止程序向下执行
        if (this.status !== PENDINGreturn;
        // 将状态改为成功
        this.status = FULFILLED;
        this.successData = successData;

        // 判断异步操作后,成功回调是否存在
        this.successCallback && this.successCallback(successData)

    };
    reject = (failData) => {
        // 如果状态不是是等待,阻止程序向下执行
        if (this.status !== PENDINGreturn;
        //将状态改为失败
        this.status = REJECTED;
        this.failData = failData;

        // 判断失败后的回调是否存在
        this.failCallback && this.failCallback(failData)
    };

    then(successCallback, failCallback) {
        // 判断状态
        if (this.status == FULFILLED) {
            successCallback(this.successData)
        } else if (this.status == REJECTED){ 
            failCallback(this.failData)
        } else {

            /**
             * 实现promise 异步逻辑的重要代码
             */
            // 异步的情况,等待异步后执行resolve 或者reject
            // 将成功或者失败的回调存储起来
            this.successCallback = successCallback;
            this.failCallback = failCallback;
        }
    }
}

// commonjs 模块化导出
module.exports = MyPromise;

实例化调用:

// 导入MyPromise
const MyPromise = require("./myPromise");

const promise = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        // resolve("成功")
        reject("失败")
    }, 2000)
    // reject("失败")
});
// console.log(promise, 222)

promise.then(success => {
    console.log(success)
}, fail => {
    console.log(fail)
})

3. promise实现链式调用

所谓的链式调用,就是可以在promise的实例化方法中无限的进行 .then() 下去 ,并且每次都返回一个promise 对象,提供给下一个then() 方法进行链式调用

实现的主要逻辑:

  1. 在then() 方法中再返回一个promise实例,这样处理的好处是,每次执行.then()后,可以返回一个新的实例化promise对象,这样,就可以在then()方法后面无限拼接链式的调用,并且拿到的是一个新的promise 对象,可以在这个新的promise 对象进行新的操作,不受上一个promise 对象的影响。
  2. 封装一个resolvePromise(),方法参数可以有 当前 .then() 的回调方法执行后的返回值。 重要的是,resolvePromise()方法中有新的promise 对象的 resolve 和reject的形参,执行的时候,就可以管理起来,在resolvePromise(x, resolve, reject)里执行了 resolve(),reject()。 从而实现了把上一个then()返回的值在当前promise对象使用,并在then()的回调函数中返回。
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
const PENDING = 'pending';

class MyPromise {
    constructor(executor) {
        // 执行器
        executor(this.resolvethis.reject)
    }

    // 状态更开始的时候是等待
    status = PENDING;

    // 保存成功后的返回值
    successData = undefined;

    // 保存失败后的返回值
    failData = undefined;
    // 保存成功的回调
    successCallback = [];

    // 保存失败的回调
    failCallback = [];

    resolve = (successData) => {
        // 如果状态不是是等待,阻止程序向下执行
        if (this.status !== PENDINGreturn;
        // 将状态改为成功
        this.status = FULFILLED;
        this.successData = successData;

        // 6.判断异步操作后,成功回调是否存在
        // 7.promise 多次调用处理逻辑
        // 每次从数组的栈中压出一个值
        
        // 方式一: 有缺陷,当第一次就存在异步的情况下,链式调用第二次会执行不了
        // while(this.successCallback.length) {
        //   this.successCallback.shift()(successData)
        // }
        // 方式二: 解决异步情况下的链式调用问题
        for(let i = 0;i< this.successCallback.length;i++) {
        let x  = this.successCallback[i].successCallback(successData)
        resolvePromise(x,this.successCallback[i].resolve,this.successCallback[i].reject)
        }
        this.successCallback = []
    };
    reject = (failData) => {
        // 如果状态不是是等待,阻止程序向下执行
        if (this.status !== PENDINGreturn;
        //将状态改为失败
        this.status = REJECTED;
        this.failData = failData;

        // 判断失败会的回调是否存在
        // 7.promise 多次调用处理逻辑
        for(let i = 0;i< this.failCallback.length;i++) {
          let x  = this.failCallback[i].failCallback(failData)
          resolvePromise(x,this.failCallback[i].resolve,this.failCallback[i].reject)
        }
        this.failCallback = []

    };

    then(successCallback, failCallback) {
        // 8.链式调用,每次then返回一个promise
        let promise2 = new MyPromise((resolve, reject) => {
            // 判断状态
            if (this.status == FULFILLED) {
                let x = successCallback(this.successData);
                resolvePromise(x, resolve, reject)
            } else if (this.status == REJECTED) {
                let y = failCallback(this.failData);
                resolvePromise(y, resolve, reject)
            } else {
                // 6.异步的情况,等待异步后执行resolve 或者reject
                // 将成功或者失败的回调存储起来

                // 7.promise 多次调用处理逻辑
                // 方式一:有缺陷,当第一次就存在异步的情况下,链式调用第二次会执行不了
                //this.successCallback.push(successCallback);
                //this.failCallback.push(failCallback);
                
                // 方式二:
                this.successCallback.push({
                  successCallback,
                  resolve,
                  reject
                });
                this.failCallback.push({
                  failCallback,
                  resolve,
                  reject
                });
            }
        });
        return promise2;
    }
}

// 判断x 是普通值还是promise对象
// 普通值直接调用resolve()
// promise对象查看返回的结果,根据结果调用resolve还会reject

/**
 * 
 * resolve,reject 是从then() 中返回的promise2 中获取的
 * 然后执行x.then(resolve,reject),也就是执行了外部的promise 对象,然后把结果放到resolve()或者reject()函数中
 *所以当then() 中 return promise2,就是携带了外部的promise 对象的执行结果的,这时只需要再 .then()就能拿到上一次的then(promise对象的结果
 */
function resolvePromise(x, resolve, reject) {
    if (x instanceof MyPromise) {
        x.then(resolve, reject)
        // 等于   
        // x.then(resolveData=>{
        //   resolve(resolveData)
        // },rejectData=>{
        //   reject(rejectData)
        // })
    } else {
        resolve(x)
    }
}

// commonjs 模块化导出
module.exports = MyPromise;

实例化调用:

进行的输出结果:

成功 success-11 other fail-222

// 导入MyPromise
const MyPromise = require("./myPromise");

const promise = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        // resolve("成功")
        // reject("失败")
    }, 2000)
    resolve("成功")

    // reject("失败")
});

function other() {
    return new MyPromise((resolve, reject) => {
      reject("other")
    })
}

promise.then(success => {  
    console.log(success,"success-111");
     // 会在callbackSuccess()中执行拿到 return other()
    return other();
}, fail => {
    console.log(fail,"fail-111");
//     return other();
}).then(success => {
    console.log(success,'success-222')
}, fail => {
    console.log(fail,"fail-222");
    return other();
})

4. promise 自调用和和其他错误状态

  1. 判断promise是否是自调用,其实原理很简单,就是在then()中的resolvePromise() 加上一个promise对象。如果当次的then()返回的是自己,那么在下一个链式调用的then()中,就判断并拦截错误,不让程序向下执行。
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
const PENDING = 'pending';

class MyPromise {
  constructor(executor) {
    // 捕获错误状态
    try {
      executor(this.resolvethis.reject)
    } catch (e) {
      this.reject(e)
    }
  }

  status = PENDING
  successData = undefined
  failData = undefined
  successCallback = []
  failCallback = []

  resolve = (successData) => {
    if (this.status !== PENDINGreturn

    this.status = FULFILLED
    this.successData = successData

    for (let i = 0; i < this.successCallback.length; i++) {
      let x = this.successCallback[i].successCallback(successData)
      resolvePromise(x, this.successCallback[i].resolvethis.successCallback[i].reject)
    }
    this.successCallback = []
  }

  reject = (failData) => {
    if (this.status !== PENDINGreturn
    this.status = REJECTED
    this.failData = failData

    for (let i = 0; i < this.failCallback.length; i++) {
      let x = this.failCallback[i].failCallback(failData)
      resolvePromise(x, this.failCallback[i].resolvethis.failCallback[i].reject)
    }
    this.failCallback = []
  }

  then(successCallback, failCallback) {
    let promise2 = new MyPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        // promise 返回自身的逻辑
        setTimeout(() => {
          // 捕获错误状态
          try {
            let x = successCallback(this.successData)
            // 加promise2 判断是否调用自身
            resolvePromise(x, resolve, reject, promise2)
          } catch (e) {
            reject(e)
          }
        }, 0)

      } else if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = failCallback(this.failData)
            // 加promise2 判断是否调用自身
            resolvePromise(x, resolve, reject, promise2)
          } catch (e) {
            // 捕获错误状态
            reject(e)
          }
        }, 0)

      } else {
        this.successCallback.push({
          successCallback,
          resolve,
          reject
        })
        this.failCallback.push({
          failCallback,
          resolve,
          reject
        })
      }
    })
    return promise2
  }

const resolvePromise = (x, resolve, reject, promise2 = null) => {
  if (promise2 === x) {
    return reject("promise 不能调用返回自身...")
  }
  if (x instanceof MyPromise) {
    x.then(resolve, reject)
  } else {
    resolve(x)
  }
}

module.exports = MyPromise

实例化调用:

输出结果: 成功回调 resolve执行... promise 不能调用返回自身... p1-reason

const MyPromise = require("./myPromise")

let promise = new MyPromise((resolve, reject) => {

  setTimeout(() => {
    // resolve("成功回调")
    // reject("失败回调")
  }, 2000)
  resolve("成功回调")
  // reject("失败")
})
let p1 = promise.then(success => {
//   throw new Error("then error")
  console.log(success, "resolve执行...")
  // 链式调用返回的一个promise对象
  return p1
}, fail => {
  // error 捕获错误状态
  console.log(fail, '捕获错误状态')
})

 p1.then(value => {                       
   console.log(value, "p1-value")
 }, reason => {
   console.log(reason, "p1-reason")
 })

  // resolve 时验证捕获错误
//   .then(value => {
//     console.log(value, "捕获错误-value")
//   }, reason => {
//     console.log(reason.message, "捕获错误-reason")
//   })


5. primise all 方法的实现

  1. Promise.all() 方法的使用是,当数组中的全部值都正常返回时,返回结果。 但是当有一个函数返回的是reject,就会终止执行,并把错误抛出。
  2. 定义一个all()静态方法,all() 静态方法 返回一个 new MyPromise()实例,接受一个数组。内部执行一个addData() 方法,辅佐判断状态逻辑。
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
const PENDING = 'pending';

class MyPromise {
  constructor(executor) {
    executor(this.resolve,this.reject)
  }

  status = PENDING 
  successData  = undefined
  failData = undefined
  successCallback = []
  failCallback = []
  
  resolve = (successData) => {
    if(this.status !==PENDING ) return

    this.status = FULFILLED
    this.successData = successData

    for(let i = 0;i< this.successCallback.length;i++) {
      let x  = this.successCallback[i].successCallback(successData)
      resolvePromise(x,this.successCallback[i].resolve,this.successCallback[i].reject)
    }
    this.successCallback = []
  }

  reject = (failData) => {
    if(this.status !== PENDING ) return
    this.status = REJECTED
    this.failData = failData

    for(let i = 0;i< this.failCallback.length;i++) {
      let x  = this.failCallback[i].failCallback(failData)
      resolvePromise(x,this.failCallback[i].resolve,this.failCallback[i].reject)
    }
    this.failCallback = []
  }

  then(successCallback,failCallback) {
    let promise2 = new MyPromise((resolve,reject)=> {
      if(this.status === FULFILLED) {
        let x = successCallback(this.successData)
        resolvePromise(x,resolve,reject)
      }else if(this.status === REJECTED) {
        // Promise.all() 方法判断
        // if()
        let x = failCallback(this.failData)
        resolvePromise(x,resolve,reject)
      }else {
        this.successCallback.push({
          successCallback,
          resolve,
          reject
        })
        this.failCallback.push({
          failCallback,
          resolve,
          reject
        })
      }
    })
    return promise2
  }
  
  /**
   * promise all的静态方法,接受一个数组
   * 该方法当内部所有值是成功时成功,其中有一个失败就是失败
   */
  static all(array) {
    // 保存执行后的值
    let results = []
    
    // 考虑实例化时 resolve 执行时的异步情况,定义一个变量,当for 循环执行完成后再调用resolve
    let index = 0;
    
    // 定义一个方法,保存每次执行的值
    // function addData(key,value) {  // 没考虑异步时的情况
    //   results[key] = value
    // }

    // all 方法 返回一个promise
    return new MyPromise((resolve,reject)=> {
      // 2.0考虑异步时的情况
      function addData(key,value) {
        results[key] = value
        index++;
        if(index === array.length) {
          // 执行 promise的resolve()
          resolve(results)
        }
      }

      // for 方法遍历数组
      for(let i=0; i<array.length; i++ ){
        let current = array[i];
        // 判断是promise 对象还是普通值
        if(current instanceof MyPromise) {
          // then方法,成功返回成功的值,有reject 失败的,就直接调用reject()返回失败
          // resolve 和 reject 只能其中一个被调用!!
          current.then(FulfilledValue=> addData(i,FulfilledValue), RejectedValue=> reject(RejectedValue))
        }else {
          // 普通值直接加入数组
          addData(i,current)
        }
      }
      // 遍历完后返回所成功的值有值
      // resolve(results)  // 1.0没考虑异步时的情况, 返回 [ 'a1', <1 empty item>, 'other2', 'b1' ]
    })
  }
}

const resolvePromise = (x,resolve,reject) => {
  if(x instanceof MyPromise) {
    x.then(resolve,reject)
  }else {
    resolve(x)
  }
}

module.exports = MyPromise

实例化调用:

输出结果: [ 'a1', 'other1', 'other2', 'b1' ]

const MyPromise = require("./MyPromise")


function other() {
    return new MyPromise((resolve, reject) => {
        setTimeout(()=> {
          resolve("other1")
        },2000)
    // reject("other1")
    })
}
function other2() {
    return new MyPromise((resolve, reject) => {
        resolve("other2")
        // reject("other2")
    })
}
MyPromise.all(['a1',other(),other2(),'b1']).then(values => {
  console.log(values);  // [ 'a1', 'other1', 'other2', 'b1' ]
},reason=> {
  console.log(reason,"失败")
});

6. then方法可选参数,promise.resolve方法,finally方法,catch方法的实现

  1. then()可选参数的实现

有回调函数就执行,没有就执行空的回调函数。可选参数实现类型promise 对象 promise.then().then().then(value => console.log(value)) ,这样的效果。其逻辑的实现原理是在then()方法中,对成功和失败的回调函数进行三目运算判断,如果存在回调函数,使用原回调函数,不存在就返回一个不处理任何逻辑的空函数,例如 (value) => {return value}。然后把获得的值在resolvePromise())又赋值给下一个then()

successCallback = successCallback ? successCallback : value => value;
failCallback = failCallback ? failCallback : fail => { throw fail };
  1. promise.resolve方法

创建一个resolve() 静态方法,在函数内部判断参数是promise对象还是一个普通值。如果是一个promise 对象,就直接返回参数。如果是一个普通值,需要new 一个promise 对象,把普通值当成参数传到promise对象的reselve中。再返回这个promise对象。 实现下面种使用,MyPromise.resolve(100).then(value => console.log(value))

static resolve(value) {
    // 判断数据是 promise 对象还是普通值
    if (value instanceof MyPromisereturn value
    // 如果是普通值,创建一个promise对象,调用resolve方法
    return new MyPromise(resolve => resolve(value))
}
  1. finally()方法

finally()方法的作用是,无论promise对象的最后结果是成功 或者失败,都会执行一次。 实现这样的效果的原理是: finally()函数返回一个this.then()函数,然后分别在成功和失败的回调函数内部,再返回一个 promise.resolve方法,把回调函数参数传进去,然后 .then() 执行各个静态方法。

// 传入一个callback 回调方法
  finally(callback) {
    // 没有加入异步等待时的实现方式
    // return this.then((value)=>{
    //   // 执行回调函数
    //   callback()
    //   return value // 返回结果,才可以进行链式调用 p2().finally(() => {}).then(()=>{})
    // },reason=> {
    //   callback()
    //   throw reason
    // })

    // 加入异步等待时的实现方式
    return this.then(value=> {
      // // 调用promise.resolve方法,返回一个promise对象,方便链式调用
      // 用resolve 静态方法,把callback回调函数放到promise中执行,就可实现异步
      return MyPromise.resolve(callback()).then(() => value)
    },reason=> {
        return MyPromise.resolve(callback()).then(() => reason)
    })
  }
  1. catch 方法

catch() 方法,只执行当存在reject时的错误的回调函数。内部也是返回一个this.then()函数。 不过有区别的是,这个then()函数,只有一个可用的失败回调函数形参。

// 只执行失败的方法
catch(failCallback) {
    return this.then(undefined, failCallback)
}

下面是完整的方法代码:

const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
const PENDING = 'pending';

class MyPromise {
  constructor(executor) {
    try {
      executor(this.resolvethis.reject)
    } catch (e) {
      this.reject(e)
    }
  }

  status = PENDING
  successData = undefined
  failData = undefined
  successCallback = []
  failCallback = []

  resolve = (successData) => {
    if (this.status !== PENDINGreturn

    this.status = FULFILLED
    this.successData = successData

    for (let i = 0; i < this.successCallback.length; i++) {
      let x = this.successCallback[i].successCallback(successData)
      resolvePromise(x, this.successCallback[i].resolvethis.successCallback[i].reject)
    }
    this.successCallback = []
  }

  reject = (failData) => {
    if (this.status !== PENDINGreturn
    this.status = REJECTED
    this.failData = failData

    for (let i = 0; i < this.failCallback.length; i++) {
      let x = this.failCallback[i].failCallback(failData)
      resolvePromise(x, this.failCallback[i].resolvethis.failCallback[i].reject)
    }
    this.failCallback = []
  }

  then(successCallback, failCallback) {
    // then可选参数实现
    // then 有回调函数就执行,没有就执行空的回调函数
    // value => value; 等于-》  (value) => {return value}, 获得的值在resolvePromise())又赋值给下一个then()
    successCallback = successCallback ? successCallback : value => value;
    failCallback = failCallback ? failCallback : fail => { throw fail };

    let promise2 = new MyPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        setTimeout(() => {
          try {
            let x = successCallback(this.successData)
            resolvePromise(x, resolve, reject, promise2)
          } catch (e) {
            reject(e)
          }
        }, 0)

      } else if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = failCallback(this.failData)
            resolvePromise(x, resolve, reject, promise2)
          } catch (e) {
            reject(e)
          }
        }, 0)

      } else {
        this.successCallback.push({
          successCallback,
          resolve,
          reject
        })
        this.failCallback.push({
          failCallback,
          resolve,
          reject
        })
      }
    })
    return promise2
  }

  /**
   * promise all的静态方法,接受一个数组
   * 该方法当内部所有值是成功时成功,其中有一个失败就是失败
   */
  static all(array) {
    // 保存执行后的值
    let results = []
    let index = 0;

    // all 方法 返回一个promise
    return new MyPromise((resolve, reject) => {
      // 2.0考虑异步时的情况
      function addData(key, value) {
        results[key] = value
        index++;
        if (index === array.length) {
          resolve(results)
        }
      }
      // for 方法遍历数组
      for (let i = 0; i < array.length; i++) {
        let current = array[i];
        if (current instanceof MyPromise) {
          current.then(FulfilledValue => addData(i, FulfilledValue), RejectedValue => reject(RejectedValue))
        } else {
          addData(i, current)
        }
      }
    })
  }

  // promise.resolve 静态方法
  static resolve(value) {
    // 判断数据是 promise 对象还是普通值
    if (value instanceof MyPromisereturn value
    // 如果是普通值,创建一个promise对象,调用resolve方法
    return new MyPromise(resolve => resolve(value))
  }

  // finally 方法
  // 传入一个callback 回调方法
  finally(callback) {
    return this.then(success => {
      // 调用promise.resolve方法,返回一个promise对象,方便链式调用
      return MyPromise.resolve(callback()).then(() => success)
    }, fail => {
      return MyPromise.resolve(callback()).then(() => fail)
    })
  }

  // catch 方法 
  // 只执行失败的方法
  catch(failCallback) {
    return this.then(undefined, failCallback)
  }

}

const resolvePromise = (x, resolve, reject, promise2 = null) => {
  if (promise2 === x) {
    return reject("promise 不能调用返回自身...")
  }
  if (x instanceof MyPromise) {
    x.then(resolve, reject)
  } else {
    resolve(x)
  }
}

module.exports = MyPromise

实例化调用:

const MyPromise = require("./MyPromise")

let promise = new MyPromise((resolve, reject) => {
  resolve('成功')
//   reject("失败")

})

function p1() {
  return new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve('成功')
    }, 200)
  })
}
function p2() {
  return new MyPromise((resolve, reject) => {
    reject('p2 reject')
  })
}

// 1 then 可选参数
 promise.then().then().then(value => console.log(value), fail => console.log(fail)) 

// 2. promise.resolve方法
// MyPromise.resolve(100).then(value => console.log(value))
// MyPromise.resolve(p1()).then(value => console.log(value))

// 3. finally 方法
//  p1().finally(() => {
//    console.log("执行 finally")
//  })
//  promise.finally(() => {
//    console.log("执行 finally-")
//  })

//  p2().finally(() => {
//    console.log("执行 finally")
//    return p1()
//  }).then((value) => {
//    console.log(value, "value")
//  }, fail => {
//    console.log(fail, "fail");
//  })

// 4. catch 方法
// promise.then(success => {
//   console.log(success, 'success')
// }).catch(fail => {
//   console.log(fail, 'fail')
// })


// finally()方法理解打印,
// other2().finally(()=> {
//   console.log("执行了finally")
// }).then((value) => {
//    console.log(value, "value")
//  }, fail => {
//    console.log(fail, "fail");
//  })
// // 没有加入异步等待时的测试
// other2().finally(() => {
//   console.log("执行了finally,没有加入异步等待时的测试")
//   return other() // 异步的
// }).then((value) => {
//   console.log(value, "value")
// }, fail => {
//   console.log(fail, "fail");
// })

// 加入异步等待时的测试,等待了两秒再输出
// other2().finally(() => {
//   console.log("执行了finally,没有加入异步等待时的测试")
//   return other() // 异步的
// }).then((value) => {
//   console.log(value, "value")
// }, fail => {
//   console.log(fail, "fail");
// })