Promise

1、发自灵魂的提问 : 什么是promise ? enenen…

a. Promise是JS异步编程中的重要概念和思想,在这个容器里面保存着某个未来才会结束的事件(通常返回一个事件结果);

Promise之前是通过回调函数来实现的但是嵌套逻辑太深
例:

const fs = require('fs');
fs.readFile('1.txt', (err,data) => {
    fs.readFile('2.txt', (err,data) => {
        fs.readFile('3.txt', (err,data) => {
            //可能还有后续代码
        });
    });
});

Promise实现可以更友好的处理抱错信息和代码可阅读性
例:

const readFile = function(fileName){
    return new Promise((resolve, reject)=>{
        fs.readFile(fileName, (err, data)=>{
            if(err){
                reject(err)
            } else {
                resolve(data)
            }
        })
    })
}

readFile('1.txt')
    .then(data => {
        return readFile('2.txt');
    }).then(data => {
        return readFile('3.txt');
    }).then(data => {
        //...
    });

2、Promise规范

Promise最早是在commonjs社区提出来的,当时提出了很多规范。比较接受的是promise/A规范。但是promise/A规范比较简单,后来人们在这个基础上,提出了promise/A+规范,也就是实际上的业内推行的规范;es6也是采用的这种规范,但是es6在此规范上还加入了Promise.all、Promise.race、Promise.catch、Promise.resolve、Promise.reject等方法。

Promise的基本使用

const promise = new Promise(function(resolve, reject){
    console.log('1')
    setTimeout(function(){
        resolve(2)
    }, 1000)
});
promise.then(function(res){
    console.log('suc',res)
},function(err){
    console.log('err',err)
})

3、Promise规范的三种状态单向不可逆

等待态(初始状态)(Pending)、执行态(Fulfilled)和拒绝态(Rejected)

// 三种状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class Promise1 {
  FULFILLED_CALLBACK_LIST = []; // pending状态存储.then成功的回调
  REJECTED_CALLBACK_LIST = []; // 失败的回调
	constructor(fn) {
    this.status = PENDING; // 初始状态
    this.value = null; // 成功结果
    this.reason = null; // 失败原因
    try {
      fn(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }
  }
}


3.1 resolve【成功】和 reject 【失败】方法设置状态值
resolve(value) {
    if (this.status === PENDING) {
      this.status = FULFILLED;
      this.value = value;
      // 把当前的指传给后面then回调
      this.FULFILLED_CALLBACK_LIST.forEach((fn) => fn(value));
    }
  }
  reject(reason) {
    if (this.status === PENDING) {
      this.status = REJECTED;
      this.reason = reason;
      this.REJECTED_CALLBACK_LIST.forEach((fn) => fn(reason));
    }
  }

4、then当Promise状态改变后不管成功还是失败都会触发then回调函数

promise.then(onFulfilled,onRejected)
  • onFulfilled 和 onRejected 都是可选参数。如果 onFulfilled 不是函数,其必须被忽略。如果 onRejected 不是函数,其必须被忽略。
  • onFulfilled/onRejected 是微任务 可用queueMicrotask 或者 setTimeout来实现微任务调用且只能调用一次。
  • Promise 状态变成fufilled时 调用onFulfilled 参数是 value 在Promise变成 fulfilled前不应该被调用
  • Promise 状态变成rejected时应该调用onRejected参数是reason在Promise变成rejected前不应该被调用

5、then方法可以被多次调用

  • promise状态变成 fulfilled 后,所有的 onFulfilled 回调都需要按照then的顺序执行, 也就是按照注册顺序执行(所以在实现的时候需要一个数组来存放多个onFulfilled的回调)
  • promise状态变成 rejected 后,所有的 onRejected 回调都需要按照then的顺序执行, 也就是按照注册顺序执行(所以在实现的时候需要一个数组来存放多个onRejected的回调)
  FULFILLED_CALLBACK_LIST = []; // 成功的回调
  REJECTED_CALLBACK_LIST = []; // 失败的回调
 
/**
   * 
   * @param {function} onFulfilled  成功回调
   * @param {function} onRejected  失败回调
   * @returns value
   */
  then(onFulfilled, onRejected) {
    /**onFulfilled/onRejected判断是否为函数 */
    const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => value;
    const rejectedFn = this.isFunction(onRejected) ? onRejected: (reason) => { throw reason; };
    if (this.status === FULFILLED) {
      const newPromise = new Promise1((resolve, reject) => {
        return setTimeout(() => {
          try {
            /**如果不是函数直接返回值 */
            if (!this.isFunction(onFulfilled)) {
              resolve(this.value);
            } else {
              /**如果是函数则继续处理数据 */
              const x = fulFilledFn(this.value);
              this.resolvePromise(newPromise, x, resolve, reject);
            }
          } catch (error) {
            reject(error);
          }
        });
      });
      return newPromise;
    } else if (this.status === REJECTED) {
      const newPromise = new Promise1((resolve, reject) => {
        return setTimeout(() => {
          try {
              /**如果不是函数直接返回抱错原因 */
            if (!this.isFunction(onRejected)) {
              reject(this.reason);
            } else {
              /**如果是函数则继续处理数据 */
              const x = rejectedFn(this.reason);
              this.resolvePromise(newPromise, x, resolve, reject);
            }
          } catch (e) {
            reject(e);
          }
        });
      });
    } else if (this.status === PENDING) {
      /***  1. 那么我们首先要拿到所有的回调, 然后才能在某个时机去执行他. 新建两个数组, 来分别存储成功和失败的回调, 调用then的时候, 如果还是pending就存入数组.*/
      const newPromise = new Promise1((resolve, reject) => {
        this.FULFILLED_CALLBACK_LIST.push(() => {
          setTimeout(() => {
            try {
              if (!this.isFunction(onFulfilled)) {
                resolve(this.value);
              } else {
                const x = fulFilledFn(this.value);
                this.resolvePromise(newPromise, x, resolve, reject);
              }
            } catch (error) {
              reject(error);
            }
          });
        });

        this.REJECTED_CALLBACK_LIST.push(() => {
          setTimeout(() => {
            try {
              if (!this.isFunction(onRejected)) {
                reject(this.reason);
              } else {
                const x = rejectedFn(this.reason);
                this.resolvePromise(newPromise, x, resolve, reject);
              }
            } catch (e) {
              reject(e);
            }
          });
        });
      });
      return newPromise;
    }
  }

6、then返回值是一个Promise

const promise2 = promise.then(onFulfilled,onRejected);
  • 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程 调用 resolvePromise
  • 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e
  • 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值
  • 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因

首先第一点,我们知道onFulfilled和onRejected执行之后都会有一个返回值x,对返回值x处理就需要用到Promise解决过程,这个我们下面再说;第二点需要对onFulfilled和onRejected进行异常处理,没什么好说的;第三和第四点,说的其实是一个问题,如果onFulfilled和onRejected两个参数没有传,则继续往下传(值的传递特性);举个例子:

const promise = new Promise(function(resolve, reject){
    setTimeout(function(){
        resolve(3)
    }, 1000)
});
promise.then(1,1)
.then('','')
.then()
.then(function(res){
    // 3
    console.log(res)
})

7、Promise解决过程resolvePromise

/**
 * 
 * @param {Promise} promise2 新Promise对象
 * @param {*} x 上一个then的返回值
 * @param {*} resolve promise2的resolve
 * @param {*} reject promise2的reject
 */
function resolvePromise(promise2, x, resolve, reject) {}

定义好函数后,来看具体的操作说明:

  1. x 与 promise 相等
  • 如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise
  1. x 为 Promise
    1. 如果 x 处于等待态, promise 需保持为等待态直至 x 被执行或拒绝
    2. 如果 x 处于执行态,用相同的值执行 promise
    3. 如果 x 处于拒绝态,用相同的据因拒绝 promise
  2. x 为对象或函数
    1. 把 x.then 赋值给 then
    2. 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
    3. 如果 then 是函数,将 x 作为函数的作用域 this 调用之。传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise:
      1. 如果 resolvePromise 以值 y 为参数被调用,则运行Resolve
      2. 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
      3. 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
      4. 如果 then 不是函数,以 x 为参数执行 promise
  3. 如果 x 不为对象或者函数,以 x 为参数执行 promise

首先第一点,如果x和promise相等,这是一种什么情况呢,就是相当于把自己返回出去了:

//Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>
const promise2 = p.then(function(){
    return promise2
})

这样会陷入一个死循环中,因此我们首先要把这种情况给排除掉:

function resolvePromise(promise2, x, resolve, reject) {
    if (promise2 === x) {
        reject(new TypeError('Chaining cycle'));
    }
}

例子:

 /**
   *
   * @param {Promise} newPromise 新Promise对象
   * @param {*} x 上一个then的返回值
   * @param {*} resolve newPromise的resolve
   * @param {*} reject newPromise的reject
   */
  resolvePromise(newPromise, x, resolve, reject) {
    if (newPromise === x) {
      return reject(new TypeError("你的小p 不能想同哦,会死循环的!"));
    }
    if (x instanceof Promise1) {
      // 如果是个promise则继续执行newPromise
      x.then((y) => {
        this.resolvePromise(newPromise, y, resolve, reject);
      }, reject);
    } else if ((x && typeof x === "object") || this.isFunction(x)) {
      // 判断是否有then
      let then = null;
      try {
        then = x.then;
      } catch (error) {
        return reject(error);
      }

      // 如果是函数
      if (this.isFunction(then)) {
        // 确保调用一次
        let called = false;
        try {
          then.call(
            x,
            (y) => {
              if (called) {
                return;
              }
              called = true;
              this.resolvePromise(newPromise, y, resolve, reject);
            },
            (r) => {
              if (called) {
                return;
              }
              called = true;
              reject(r);
            }
          );
        } catch (error) {
          if (called) return;
          reject(error);
        }
      }
    } else {
      resolve(x);
    }
  }

8、完整代码

// 三种状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class Promise1 {
  FULFILLED_CALLBACK_LIST = []; // 成功的回调
  REJECTED_CALLBACK_LIST = []; // 失败的回调

  constructor(fn) {
    this.status = PENDING;
    this.value = null; // 成功结果
    this.reason = null; // 失败原因
    try {
      fn(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }
  }

  resolve(value) {
    if (this.status === PENDING) {
      this.status = FULFILLED;
      this.value = value;
      this.FULFILLED_CALLBACK_LIST.forEach((fn) => fn(value));
    }
  }

  reject(reason) {
    if (this.status === PENDING) {
      this.status = REJECTED;
      this.reason = reason;
      this.REJECTED_CALLBACK_LIST.forEach((fn) => fn(reason));
    }
  }

  /**
   * 判断是否为函数
   * @param {any} param 
   * @returns 
   */
  isFunction(param) {
    return typeof param === "function";
  }

  /**
   * 
   * @param {function} onFulfilled  成功回调
   * @param {function} onRejected  失败回调
   * @returns value
   */
  then(onFulfilled, onRejected) {
    /**onFulfilled/onRejected判断是否为函数 */
    const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => value;
    const rejectedFn = this.isFunction(onRejected) ? onRejected: (reason) => { throw reason; };


    if (this.status === FULFILLED) {
      const newPromise = new Promise1((resolve, reject) => {
        return setTimeout(() => {
          try {
            /**如果不是函数直接返回值 */
            if (!this.isFunction(onFulfilled)) {
              resolve(this.value);
            } else {
              /**如果是函数则继续处理数据 */
              const x = fulFilledFn(this.value);
              this.resolvePromise(newPromise, x, resolve, reject);
            }
          } catch (error) {
            reject(error);
          }
        });
      });
      return newPromise;
    } else if (this.status === REJECTED) {
      const newPromise = new Promise1((resolve, reject) => {
        return setTimeout(() => {
          try {
              /**如果不是函数直接返回抱错原因 */
            if (!this.isFunction(onRejected)) {
              reject(this.reason);
            } else {
              /**如果是函数则继续处理数据 */
              const x = rejectedFn(this.reason);
              this.resolvePromise(newPromise, x, resolve, reject);
            }
          } catch (e) {
            reject(e);
          }
        });
      });
    } else if (this.status === PENDING) {
      /*** */
      const newPromise = new Promise1((resolve, reject) => {
        this.FULFILLED_CALLBACK_LIST.push(() => {
          setTimeout(() => {
            try {
              if (!this.isFunction(onFulfilled)) {
                resolve(this.value);
              } else {
                const x = fulFilledFn(this.value);
                this.resolvePromise(newPromise, x, resolve, reject);
              }
            } catch (error) {
              reject(error);
            }
          });
        });

        this.REJECTED_CALLBACK_LIST.push(() => {
          setTimeout(() => {
            try {
              if (!this.isFunction(onRejected)) {
                reject(this.reason);
              } else {
                const x = rejectedFn(this.reason);
                this.resolvePromise(newPromise, x, resolve, reject);
              }
            } catch (e) {
              reject(e);
            }
          });
        });
      });
      return newPromise;
    }
  }




  /**
   *
   * @param {Promise} newPromise 新Promise对象
   * @param {*} x 上一个then的返回值
   * @param {*} resolve newPromise的resolve
   * @param {*} reject newPromise的reject
   */
  resolvePromise(newPromise, x, resolve, reject) {
    if (newPromise === x) {
      return reject(new TypeError("你的小p 不能想同哦,会死循环的!"));
    }
    if (x instanceof Promise1) {
      // 如果是个promise则继续执行newPromise
      x.then((y) => {
        this.resolvePromise(newPromise, y, resolve, reject);
      }, reject);
    } else if ((x && typeof x === "object") || this.isFunction(x)) {
      // 判断是否有then
      let then = null;
      try {
        then = x.then;
      } catch (error) {
        return reject(error);
      }

      // 如果是函数
      if (this.isFunction(then)) {
        // 确保调用一次
        let called = false;
        try {
          then.call(
            x,
            (y) => {
              if (called) {
                return;
              }
              called = true;
              this.resolvePromise(newPromise, y, resolve, reject);
            },
            (r) => {
              if (called) {
                return;
              }
              called = true;
              reject(r);
            }
          );
        } catch (error) {
          if (called) return;
          reject(error);
        }
      }
    } else {
      resolve(x);
    }
  }
}

async function haha() {
  const a = await new Promise1((resolve, reject) => {
    // console.log("222");
    resolve("hahah");
  })
    .then((value) => {
      console.log(value, "value");
      return "---11";
    })
    .then((value) => {
      console.log(value, "-valuevalue--");
      return value + "----";
    });

  console.log(a, "aaa");
}
haha();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值