不手动撸一个 Promise,永远不能彻底了解它的运作原理。
再来复习下 Promise 的组成要素:
1. 三种状态
2. 两个参数
resolve, reject,都是函数
执行 resolve(),状态设置为 fulfilled,逻辑走到 then 中去;执行 rejected(),状态设置为 rejected,逻辑走到 catch 中去;
注意,状态只能改变一次,只能由 pending 变成 fulfilled 或 rejected,不可逆。
了解了这些,开始动手。
首先实现一个简易版 Promise,涵盖了核心概念。
class Promise1 {constructor(executor) {// executor是实例化传过来的函数// 1. 定义resolve和reject函数,第2部会用到var resolve = (value) => {if (this.status !== 'pending') return;this.status = 'fulfilled';if (this.thenCallback) {this.thenCallback(value);}};var reject = (error) => {if (this.status !== 'pending') return;this.status = 'rejected';if (this.errorCallback) {this.errorCallback(error);}};// 2. 调用executor执行函数体内的逻辑。同时,再把定义好的resolve,reject函数传回去,等待函数体内调用。try {executor(resolve, reject);} catch (e) {reject(e);}}status = 'pending';thenCallback = null;errorCallback = null;then(fn, errFn) {// 将传来的函数暂存,等待resolve或reject调用if (this.status == 'pending') {this.thenCallback = fn;this.errorCallback = errFn || null;}}catch(fn) {this.errorCallback = fn;}}
使用方法:
function getAsync(val) {return new Promise1(function (resolve, reject) {setTimeout(() => {resolve(val);}, 1000);});}getAsync('data').then((val) => {console.log(val);}).catch((e) => {console.log(e);});
这个简易版 Promise 已经可以使用了。
但为什么说是简易版?因为还缺少一个核心功能:链式调用
链式调用是这样的:
getAsync('data').then((val) => {console.log(val); // datareturn getAsync('data2');}).then((val) => {console.log(val); // data2}).catch((e) => {console.log(e);});
看出来了吗,这里多了两个点:
先看第一点。then 方法之后能继续调用 then,说明 then 方法返回的是一个 Promise(即当前构造函数 Promise1)。所以改造 then 方法。
then(fn, errFn) {return new Promise1(function (resolve, reject) {// 将传来的函数暂存,等待resolve或reject调用if(this.status == 'pending') {this.thenCallback = fn;this.errorCallback = errFn || null;}})}
再看第二点。resolve 函数有返回值,并传给下一个 resolve。所以要在 resolve 函数中获取返回,并且在 then 中使用。同时改造 resolve 和 then 方法。
var resolve = value => {if(this.status!=='pending') return;this.status = 'fulfilled';this.value = valuethis.then()}then(fn, errFn) {return new Promise1(function (resolve, reject) {// 将传来的函数暂存,等待resolve或reject调用if(this.status == 'pending') {this.thenCallback = fn;this.errorCallback = errFn || null;}if(this.status == 'fulfilled') {var result = thenCallback()if(result instanceof Promise1) {result.then(resolve, reject)} else {resolve(result)}}})}