百行代码带你实现通过872条Promise/A+用例的Promise

大厂技术  高级前端  Node进阶

点击上方 程序员成长指北,关注公众号

回复1,加入高级Node交流群

前言

一直听说想成为一名高级前端程序员需要理解一些源码,那就从 Promise 开始吧,作者尽量用最少的语言让你理解 Promise

准备

Promises/A+原文[2]
Promises/A+译文[3]

安装 Promise 测试工具

npm i promises-aplus-tests -g
复制代码

运行测试工具,检测 Promise 是否符合规范

promises-aplus-tests [promise文件名]

复制代码

完整代码先过用例

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
  constructor(executor) {
    if (typeof executor !== 'function') {
      return new TypeError(`Promise resolver ${executor} is not a function`);
    }
    this.state = PENDING;
    this.value = null;
    this.reason = null;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];
    const resolve = (value) => {
      if (this.state === PENDING) {
        this.state = FULFILLED;
        this.value = value;
        this.onFulfilledCallbacks.forEach((fn) => fn());
      }
    };
    const reject = (reason) => {
      if (this.state === PENDING) {
        this.state = REJECTED;
        this.reason = reason;
        this.onRejectedCallbacks.forEach((fn) => fn());
      }
    };
    try {
      executor(resolve, reject);
    } catch (e) {
      this.reject(e);
    }
  }
  then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function') {
      onFulfilled = (value) => value;
    }
    if (typeof onRejected !== 'function') {
      onRejected = (err) => {
        throw err;
      };
    }
    let promise2 = new Promise((resolve, reject) => {
      if (this.state === FULFILLED) {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      }
      if (this.state === REJECTED) {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      }
      if (this.state === PENDING) {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
        });
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
        });
      }
    });
    return promise2;
  }
}

const resolvePromise = (promise2, x, resolve, reject) => {
  if (promise2 === x)
    return reject(
      new TypeError('Chaining cycle detected for promise #<Promise>')
    );

  if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
    let called;
    try {
      const then = x.then;
      if (typeof then !== 'function') resolve(x);
      else {
        then.call(
          x,
          (value) => {
            if (called) return;
            called = true;

            resolvePromise(promise2, value, resolve, reject);
          },
          (reason) => {
            if (called) return;
            called = true;
            reject(reason);
          }
        );
      }
    } catch (err) {
      if (called) return;
      called = true;
      reject(err);
    }
  } else {
    resolve(x);
  }
};

Promise.defer = Promise.deferred = function () {
  let dfd = {};
  dfd.promise = new Promise((resolve, reject) => {
    dfd.resolve = resolve;
    dfd.reject = reject;
  });
  return dfd;
};
module.exports = Promise;


复制代码

完整代码127行,增加 Promise 测试代码一共 136 行代码。

如何测试

在 VS Code 新建文件 promise.jspromise.jspromise.js 文件

// promise代码
class Promise {
  constructor() {}
  then() {}
  catch() {}
}

// 测试代码
Promise.defer = Promise.deferred = function () {
  let dfd = {};
  dfd.promise = new Promise((resolve, reject) => {
    dfd.resolve = resolve;
    dfd.reject = reject;
  });
  return dfd;
};
module.exports = Promise;
复制代码

在 promise.jspromise.jspromise.js 文件所在目录打开终端,输入下面命令即可测试 Promise 是否符合规范

promises-aplus-tests promise.js
复制代码

后续讲解,不再解释测试代码,只讨论 Promise 代码了

请紧跟思路,本篇文章核心开始了

声明 Promise 类

Promise 常用的有 then 方法 和 catch,先用 ES6 语法声明一个 Promise 类

这点不难理解吧?

class Promise {
  constructor() {}
  then() {}
  catch() {}
}
复制代码

constructor

正常使用 Promise 一般 如下图所示, new Promise(参数是一个函数)

let p1 = new Promise((resolve) => {
  setTimeout(() => {
    resolve(1);
  }, 1000);
});
复制代码

所以 在 Promise 类的 constructor 使用 executor 形参接收这个参数,这点不难理解吧?

class Promise {
  constructor(executor) {}
  then() {}
  catch() {}
}
复制代码

继续:

executor 是用户输入的参数,咱们不能相信用户一定会使用一个函数作为 new Promise(参数) 对不对?

所以这里就需要判断一下 executor 是否是一个函数。

很好理解吧?

class Promise {
  constructor(executor) {
    if (typeof executor !== 'function') {
      return new TypeError(`Promise resolver ${executor} is not a function`);
    }
  }
  then() {}
  catch() {}
}
复制代码

executor

constructor 这节已经知道 executor 是个函数了,executor 函数也是有参数的呀。

如下 Promise 使用代码

let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    Math.random() > 0.5 ? resolve('正确') : reject('错误');
  }, 1000);
});
p1.then((value) => {
  console.log(value);
});
复制代码
61accc342c83648c881bda28924b4875.png
image.png

Promises/A+ 规范中说:resolve 是进行成功的一系列操作,reject 是失败的一些操作,还有成功原因,失败原因?这些咱们的 Promise 都要有,都加上

resolve 和 reject

class Promise {
  constructor(executor) {
    if (typeof executor !== 'function') {
      return new TypeError(`Promise resolver ${executor} is not a function`);
    }

    // promise 被解决时传递给解决回调的值
    this.value = null;

    // promise 被拒绝时传递给解决回调的值
    this.reason = null;

    // 成功的一系列操作
    const resolve = () => {};

    //失败的一些操作
    const reject = () => {};
    executor(resolve, reject);
  }
  then() {}
  catch() {}
}
复制代码

状态

Promises/A+译文[4]

363b9036846d06e9f8e2f438b5823005.png
image.png

Promises/A+ 规范中说,Promise 要有 3 种状态。咱们在代码中将这三种状态加上,这很好理解吧

常量命名用大写,这点可以理解的

PENDING 、FULFILLED 和 REJECTED

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
  constructor(executor) {
    if (typeof executor !== 'function') {
      return new TypeError(`Promise resolver ${executor} is not a function`);
    }
  }
  then() {}
  catch() {}
}
复制代码

要求说,Pending 状态只能去 Fulfilled 或者 Rejected 且不可变,这就需要一个变量记录 Promise 状态值, 并且状态值初始值为 Pending 这点可以理解吧

this.state

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
  constructor(executor) {
    if (typeof executor !== 'function') {
      return new TypeError(`Promise resolver ${executor} is not a function`);
    }
    this.state = PENDING;
    this.value = null;
    this.reason = null;
    const resolve = () => {};
    const reject = () => {};
    executor(resolve, reject);
  }
  then() {}
  catch() {}
}
复制代码

Pending 状态只能去 Fulfilled 或者 Rejected 意味着 resolve 和 reject 只有在 Pending 可以执行,没问题吧。

所以需要在 resolve 和 reject 函数中加判断

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
  constructor(executor) {
    if (typeof executor !== 'function') {
      return new TypeError(`Promise resolver ${executor} is not a function`);
    }
    this.state = PENDING;
    this.value = null;
    this.reason = null;
    const resolve = () => {
      // PENDING状态才能执行,执行完成修改状态为FULFILLED
      if (this.state === PENDING) {
        this.state = FULFILLED;
      }
    };
    const reject = () => {
      // PENDING状态才能执行,执行完成修改状态为 REJECTED
      if (this.state === PENDING) {
        this.state = REJECTED;
      }
    };
    executor(resolve, reject);
  }
  then() {}
  catch() {}
}
复制代码

执行完成功或者异常函数是不是要有成功或者异常数据呀,这些回调的值是不是需要保存到类中,在 then 方法中返回?

添加上

value 和 reason

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
  constructor(executor) {
    if (typeof executor !== 'function') {
      return new TypeError(`Promise resolver ${executor} is not a function`);
    }
    this.state = PENDING;
    this.value = null;
    this.reason = null;
    const resolve = (value) => {
      if (this.state === PENDING) {
        this.state = FULFILLED;

        // 解决时传递给解决回调的值
        this.value = value;
      }
    };
    const reject = (reason) => {
      if (this.state === PENDING) {
        this.state = REJECTED;

        // 拒绝时传递给解决回调的值
        this.reason = reason;
      }
    };
    executor(resolve, reject);
  }
  then() {}
  catch() {}
}
复制代码

constructor 这就完成了吗?不,还差一步。

executor 是个函数,这在上文中有描述,但是函数有没有可能执行错误,直接执行这个函数报错,报错怎么处理?try/catch 大法喽

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
  constructor(executor) {
    if (typeof executor !== 'function') {
      return new TypeError(`Promise resolver ${executor} is not a function`);
    }
    this.state = PENDING;
    this.value = null;
    this.reason = null;
    const resolve = (value) => {
      if (this.state === PENDING) {
        this.state = FULFILLED;

        // 解决时传递给解决回调的值
        this.value = value;
      }
    };
    const reject = (reason) => {
      if (this.state === PENDING) {
        this.state = REJECTED;

        // 拒绝时传递给解决回调的值
        this.reason = reason;
      }
    };
    try {
      // 如果函数顺利执行,执行函数
      executor(resolve, reject);
    } catch (error) {
      // 函数抛出异常,将异常信息通过 reject 返回
      reject(error);
    }
  }
  then() {}
  catch() {}
}
复制代码

Then

单独写 then 这个函数,暂时忽略 constructor 代码吧。代码太多容易混淆。读者觉得呢?

then() {}
复制代码

Promises/A+译文[5]

6879dbf8423ae4912eed09a9d4524fe9.png
image.png

根据规范中规定 then 要有两个参数,并且这两个参数需要是函数,如果不是函数需要忽略

所以 then 代码如下;不难理解吧

then(onFulfilled, onRejected){
    if (typeof onFulfilled !== 'function') {
      onFulfilled = (value) => value;
    }
    if (typeof onRejected !== 'function') {
      onRejected = (err) => {
        throw err;
      };
    }
}
复制代码

onFulfilled 和 onRejected

接着看规范描述

b8e547a87521396b61856be72014dee0.png
image.png

onFulfilled和onRejected调用次数不可超过一次,

then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function') {
      onFulfilled = (value) => value;
    }
    if (typeof onRejected !== 'function') {
      onRejected = (err) => {
        throw err;
      };
    }

    // 只执行一次
    if (this.state === Promise.FULFILLED) {
      onFulfilled(this.value);
    }

    if (this.state === Promise.REJECTED) {
      onRejected(this.reason);
    }
  }

复制代码

resolve 支持异步

这样就可以了吗??不不不

如果 Promise 中 resolve 是在异步函数中执行的,目前我写的 Promise 代码中 console 并不会执行。

let p2 = new Promise((resolve) => {
  setTimeout(() => {
    resolve(2);
  }, 1000);
});
p2.then((value) => {
  console.log(value);
});
复制代码

原因是执行 .then函数的时候 Promise 状态是 Pending ,当前我在 Promise.then方法中只写了 状态为 FULFILLEDREJECTED 的处理

所以.then函数还要处理状态位PENDING 的处理,pending 状态下,将.then 函数的入参先放在数组中,在异步执行 resolve 是调用

还有问题吗?

有的

then异步

console.log(1);
let p2 = new Promise((resolve) => {
  resolve(4);
  console.log(2);
});
p2.then((value) => {
  console.log(value);
});
console.log(3);
//  1,2,3,4
复制代码

正常返回 1,2,3,4 现在我写的 promise 返回 1、2、4、3

什么原因呢?原因是 .then 中的函数立即执行了,这不符合标准呀,解决办法是给 .then 函数添加 setTimeout 模拟异步

then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function') {
      onFulfilled = (value) => value;
    }
    if (typeof onRejected !== 'function') {
      onRejected = (err) => {
        throw err;
      };
    }

    if (this.state === FULFILLED) {
      setTimeout(() => {
        onFulfilled(this.value);
      });
    }

    if (this.state === REJECTED) {
      setTimeout(() => {
        onRejected(this.reason);
      });
    }
    if (this.state === PENDING) {
      this.onFulfilledCallbacks.push(() => {
        setTimeout(() => {
          onFulfilled(this.value);
        });
      });
      this.onRejectedCallbacks.push(() => {
        setTimeout(() => {
          onRejected(this.reason);
        });
      });
    }
    let promise2 = new Promise(() => {});
    return promise2;
  }
}
复制代码

Promise 的数组需要在 constructor 中声明,并且在 resolve 中执行,所以代码 Promise 到这里全部代码如下:

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
  constructor(executor) {
    if (typeof executor !== 'function') {
      return new TypeError(`Promise resolver ${executor} is not a function`);
    }
    this.state = PENDING;
    this.value = null;
    this.reason = null;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];
    const resolve = (value) => {
      if (this.state === PENDING) {
        this.state = FULFILLED;
        this.value = value;
        this.onFulfilledCallbacks.forEach((fn) => fn());
      }
    };
    const reject = (reason) => {
      if (this.state === PENDING) {
        this.state = REJECTED;
        this.reason = reason;
        this.onRejectedCallbacks.forEach((fn) => fn());
      }
    };
    try {
      executor(resolve, reject);
    } catch (e) {
      this.reject(e);
    }
  }

  then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function') {
      onFulfilled = (value) => value;
    }
    if (typeof onRejected !== 'function') {
      onRejected = (err) => {
        throw err;
      };
    }

    if (this.state === FULFILLED) {
      setTimeout(() => {
        onFulfilled(this.value);
      });
    }

    if (this.state === REJECTED) {
      setTimeout(() => {
        onRejected(this.reason);
      });
    }
    if (this.state === PENDING) {
      this.onFulfilledCallbacks.push(() => {
        setTimeout(() => {
          onFulfilled(this.value);
        });
      });
      this.onRejectedCallbacks.push(() => {
        setTimeout(() => {
          onRejected(this.reason);
        });
      });
    }
  }
}
复制代码

写到这里,我去测试了一下显示有 806 个异常;也就是说通过了 66 个测试用例。继续努力

then如何返回一个新的Promise

接着看规范描述: 26dd3abd2c16257dcc252cde71c2b39b.png

then  方法必须返回一个  promise  对象

then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function') {
      onFulfilled = (value) => value;
    }
    if (typeof onRejected !== 'function') {
      onRejected = (err) => {
        throw err;
      };
    }


    if (this.state === FULFILLED) {
      setTimeout(() => {
        onFulfilled(this.value);
      });
    }

    if (this.state === REJECTED) {
      setTimeout(() => {
        onRejected(this.reason);
      });
    }
    if (this.state === PENDING) {
      this.onFulfilledCallbacks.push(() => {
        setTimeout(() => {
          onFulfilled(this.value);
        });
      });
      this.onRejectedCallbacks.push(() => {
        setTimeout(() => {
          onRejected(this.reason);
        });
      });
    }
    // 返回一个新的 promise 对象
    let promise2 = new Promise(() => {});
    return promise2;
  }
复制代码

可以理解吧?每次 .then 都返回一个新的 promise 对象,.then 方法是不是就可以一直调用下去了

这里为什么不可以直接返回 this,比如 jQuery 不就是直接返回 this 实现链式调用的吗?

因为 promise 有 3 种状态,且状态不可逆,所以必须返回一个新的 promise 对象

then返回Promise解决过程

接着看规范描述:

  • 如果  onFulfilled  或者  onRejected  返回一个值  x ,则运行下面的  Promise 解决过程[[Resolve]](promise2, x)

  • 如果  onFulfilled  或者  onRejected  抛出一个异常  e ,则  promise2  必须拒绝执行,并返回拒因  e

  • 如果  onFulfilled  不是函数且  promise1  成功执行, promise2  必须成功执行并返回相同的值

  • 如果  onRejected  不是函数且  promise1  拒绝执行, promise2  必须拒绝执行并返回相同的据因

第一句

需要确定, onFulfilled  或者  onRejected  返回一个值  x要执行 Promise2

修改 then 代码如下:

then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function') {
      onFulfilled = (value) => value;
    }
    if (typeof onRejected !== 'function') {
      onRejected = (err) => {
        throw err;
      };
    }

    let promise2 = new Promise((resolve, reject) => {
      if (this.state === FULFILLED) {
        setTimeout(() => {
         const x = onFulfilled(this.value);
        });
      }

      if (this.state === REJECTED) {
        setTimeout(() => {
          const x = onRejected(this.reason);
        });
      }
      if (this.state === PENDING) {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
           const x =  onFulfilled(this.value);
          });
        });
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
           const x =  onRejected(this.reason);
          });
        });
      }
    });
    return promise2;
  }
}
复制代码

第二句

如果  onFulfilled  或者  onRejected  抛出一个异常  e ,则  promise2  必须拒绝执行,并返回拒因  e

使用 try/catch 捕捉  onFulfilled  或者  onRejected 抛出的异常

then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function') {
      onFulfilled = (value) => value;
    }
    if (typeof onRejected !== 'function') {
      onRejected = (err) => {
        throw err;
      };
    }

    let promise2 = new Promise((resolve, reject) => {
      if (this.state === FULFILLED) {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
          } catch (error) {
            reject(error);
          }
        });
      }

      if (this.state === REJECTED) {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
          } catch (error) {
            reject(error);
          }
        });
      }
      if (this.state === PENDING) {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value);
            } catch (error) {
              reject(error);
            }
          });
        });
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.reason);
            } catch (error) {
              reject(error);
            }
          });
        });
      }
    });
    return promise2;
  }
复制代码

第三句

如果  onFulfilled  不是函数且  promise1  成功执行, promise2  必须成功执行并返回相同的值

promise2 执行成功并返回值,这句简单,在返回 x 的地方直接 resolve(x) 不就可以了吗?

then(onFulfilled, onRejected) {
  if (typeof onFulfilled !== 'function') {
    onFulfilled = (value) => value;
  }
  if (typeof onRejected !== 'function') {
    onRejected = (err) => {
      throw err;
    };
  }

  let promise2 = new Promise((resolve, reject) => {
    if (this.state === FULFILLED) {
      setTimeout(() => {
        try {
          const x = onFulfilled(this.value);
          resolve(x);
        } catch (error) {
          reject(error);
        }
      });
    }

    if (this.state === REJECTED) {
      setTimeout(() => {
        try {
          const x = onRejected(this.reason);
          // 这里直接 resolve 并并且返回 x
          resolve(x);
        } catch (error) {
          reject(error);
        }
      });
    }
    if (this.state === PENDING) {
      this.onFulfilledCallbacks.push(() => {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            resolve(x);
          } catch (error) {
            reject(error);
          }
        });
      });
      this.onRejectedCallbacks.push(() => {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            resolve(x);
          } catch (error) {
            reject(error);
          }
        });
      });
    }
  });
  return promise2;
}
复制代码

如果 x 是基本数据类型可以,考虑一下,如果 x 是引用数据类型,是函数,甚至是 Promise 呢?

所以这里需要对 x 的数据类型判断

既然自成一体,索性增加一个方法执行这些 x 值

方法名为:resolvePromise

then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function') {
      onFulfilled = (value) => value;
    }
    if (typeof onRejected !== 'function') {
      onRejected = (err) => {
        throw err;
      };
    }

    let promise2 = new Promise((resolve, reject) => {
      if (this.state === FULFILLED) {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        });
      }

      if (this.state === REJECTED) {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        });
      }
      if (this.state === PENDING) {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          });
        });
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          });
        });
      }
    });
    return promise2;
  }

  function resolvePromise(promise2, x, resolve, reject){

  }
复制代码

resolvePromise

接下来开始写 resolvePromise 这个函数

判断 x 只不是 promise 自己

promise 不能循环调用,

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(
      new TypeError('Chaining cycle detected for promise #<Promise>')
    );
  }
}
复制代码

判断 x 是不是引用数据类型

如果不是引用数据类型,直接执行 resolve(x)

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(
      new TypeError('Chaining cycle detected for promise #<Promise>')
    );
  }
  if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
  } else {
    resolve(x);
  }
}
复制代码

如果是引用数据类型,判断数据中是否有 then 这个属性,如果有 then 不是函数,直接执行 resolve(x)

这里解释一下:如果 then 是函数,表示 x 可能是 Promise 对象,需要特殊处理,如果不是函数,当作一般对象处理

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(
      new TypeError('Chaining cycle detected for promise #<Promise>')
    );
  }
  if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
    const then = x.then;
    if (typeof then !== 'function') {
      resolve(x);
    } else {
    }
  } else {
    resolve(x);
  }
}
复制代码

当然,只要是代码就有可能出现异常,所以这里需要 try/catch 捕捉一些可能的异常

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(
      new TypeError('Chaining cycle detected for promise #<Promise>')
    );
  }
  if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
    try {
      const then = x.then;
      if (typeof then !== 'function') {
        resolve(x);
      } else {
      }
    } catch (err) {
      reject(err);
    }
  } else {
    resolve(x);
  }
}
复制代码

如果 then 是函数

then 是函数,执行 then。因为此时的 then 是从 x 上获取的,所以要调用 call 方法将 then 函数的 this 重新指向 x

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(
      new TypeError('Chaining cycle detected for promise #<Promise>')
    );
  }
  if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
    try {
      const then = x.then;
      if (typeof then !== 'function') {
        resolve(x);
      } else {
        then.call(
          x,
          (value) => {
            resolvePromise(promise2, value, resolve, reject);
          },
          (reason) => {
            reject(reason);
          }
        );
      }
    } catch (err) {
      reject(err);
    }
  } else {
    resolve(x);
  }
}
复制代码

上述代码基本完成了 Promise 的功能,但是还有一点规范文档上说:
如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用

这需要增加标识位 calledcalledcalled , called为true直接返回,

const resolvePromise = (promise2, x, resolve, reject) => {
  if (promise2 === x)
    return reject(
      new TypeError('Chaining cycle detected for promise #<Promise>')
    );

  if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
    let called;
    try {
      const then = x.then;
      if (typeof then !== 'function') resolve(x);
      else {
        then.call(
          x,
          (value) => {
            if (called) return;
            called = true;

            resolvePromise(promise2, value, resolve, reject);
          },
          (reason) => {
            if (called) return;
            called = true;
            reject(reason);
          }
        );
      }
    } catch (err) {
      if (called) return;
      called = true;
      reject(err);
    }
  } else {
    resolve(x);
  }
};
复制代码

结语

虽然我想用尽量少的语言去描述或者讲解这个 Promise 。但是最后依然用了将近4000字描述这个东西是什么。作者目前水平有限,只得尽量将 Promise 描述清楚。如有任何意见和建议欢迎评论区留言讨论。

关于本文

作者:北斗落凡尘

https://juejin.cn/post/7065693195799265287

Node 社群


我组建了一个氛围特别好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你对Node.js学习感兴趣的话(后续有计划也可以),我们可以一起进行Node.js相关的交流、学习、共建。下方加 考拉 好友回复「Node」即可。

如果你觉得这篇内容对你有帮助,我想请你帮我2个小忙:

1. 点个「在看」,让更多人也能看到这篇文章2. 订阅官方博客 www.inode.club 让我们一起成长

点赞和在看就是最大的支持❤️

猜你喜欢

转载自blog.csdn.net/xgangzai/article/details/124185937