手写Promise 2.0

671 阅读3分钟

前言

很久很久以前,手写过一个promise1.0,今天 是对其做一些补充。

x返回的是一个promise对象处理

思路

  1. If promise and x refer to the same object, reject promise with a TypeError as the reason.

如果promise2===x的时候 文档是要求拒绝这个promise 执行reject

  if (promise2 === x) {
    return reject(new TypeError("错误"));
  }
  1. Otherwise, if x is an object or function,
  if ((typeof x === "object" && x !== null) || typeof x === "function") {}
  1. 挑了我看得懂的部分 (阅读水平就这么回事了,求勿喷)
  • let then = x.then;
    Let then be x.then
  • 捕获上一个then的错误 做参数传给 这个then的 catch If retrieving the property x.then results in a thrown exception e, reject promise with e as the reason.
  • then是一个函数,this指向x,第一参数 里 resolvePromise(promise2, y, resolve, reject);递归,继续判断下一个then,直到x是普通值,然后resolve(x),第二参数里,直接reject(r)
    1. If then is a function, call it with x as this, first argument resolvePromise, and second argument rejectPromise, where
    2. If/when resolvePromise is called with a value y, run [[Resolve]](promise, y).
    3. If/when rejectPromise is called with a reason r, reject promise with r

代码

// 利用x的值来判断是调用promise的resolve还是reject
function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError("错误"));
  }
  if ((typeof x === "object" && x !== null) || typeof x === "function") {
    let called = false;
    try {
      let then = x.then; 
      if (typeof then === "function") {
        then.call(
          x,
          (y) => {
            if (called) return;
            called = true;
            resolvePromise(promise2, y, resolve, reject);
          },
          (r) => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      } else {
        //then就是一个空对象{},或者 {then:{}}
        resolve(x);
      }
    } catch (e) {
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    // x返回值是一个普通值,直接传入promises2的resolve中
    resolve(x);
  }
}

调用

  • class Promise 上的then方法里 if (this.status === FULFILLED)
  • 顺便做一个优化,包裹setTimeout ,then也是异步的 所以用setTimeout包裹,否则resolvePromise拿不到promise2
  • 上一个then执行结果x作为当前then的resolve的入参数 1. 这里要注意 只要上一个then有return 值 就调用当前then的resolve 捕获了异常才调用reject 2. x的值可能是一个promise,如果是promise需要看下这个promise是成功还是失败 3. 如果成功 则把成功的结果 调用promise2的resolve传递进去,如果失败也同理,直接catch 4. x的值决定调用promise2的resolve还是reject,如果是promise则取他的状态,如果是普通值则调用resolve 5. resolvePromise用于处理 x的返回值
if (this.status === FULFILLED) {
        setTimeout(() => {
          //   函数执行时的throw Error的处理,
          try {
            let x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (err) {
            reject(err);
          }
        }, 0);
      }
   if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            // 上一个then执行结果x作为当前then的reject的入参数
            let x = onRejected(this.reason);
            // 这里要注意 只要上一个then有return 值 就调用当前then的resolve 捕获了异常才调用reject
            resolve(x);
          } catch (err) {
            reject(err);
          }
        }, 0);
      }

Promise 静态方法的实现

resolve

返回一个new Promise 直接调用resolve

  static resolve(value) {
    return new Promise((resolve, reject) => {
      resolve(value);
    });
  }

reject

思路 同 resolve

  static reject(value) {
    return new Promise((resolve, reject) => {
      reject(value);
    });
  }

all

static all(promises) {
    //同步并发
    return new Promise((resolve, reject) => {
      let result = [];
      let times = 0;
      const processSuccess = (index, val) => {
        result[index] = val;
        // 这里为什么不直接用result.length===promises.length
        // 无法准确直到 执行结果
        if (++times === promises.length) {
          resolve(result);
        }
      };
      for (let i = 0; i < promises.length; i++) {
        let p = promises[i];
        // if (p instanceof Promise)
        // if(p&&typeof p.then==='function')
        if (p && typeof p.then === "function") {
          p.then((data) => {
            processSuccess(i, data);
          }, reject);
        } else {
          processSuccess(i, p);
        }
      }
    });
  }

race

 static race(promises) {
    return new Promise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        let p = promises[i];
        if (p && typeof p.then === "function") {
          p.then(resolve, reject); //一旦成功就直接 停止
        } else {
          resolve(p);
        }
      }
    });
  }

Promise 原型方法

catch

  catch(errFn) {
    return this.then(null, errFn);
  }

finally

  • 保证cb是一个promise的时候 用Promise.resolve包裹可以保证内部promise执行完毕
  • 直接传递上一个promise的执行结果做下一个then的回调函数的参数
finally(cb) {
    return this.then(
      (data) => {
        return Promise.resolve(cb()).then(() => data);
      },
      (err) => {
        return Promise.resolve(cb()).then(() => {
          throw err;
        });
      }
    );
  }

最后 npm install promise-aplus-test安装promise 测试 做校验

小结:终于把坑填上