一、前言
经过前面promise的基础学习,已经知道了promise的基本用法。但为了能在用promise的时候遇到问题时,能够精准定位问题和解决问题,需要对promise有个更深层次的认识。所以我们可以去手写个自己的pormise来增加对promise的理解。
我们知道,promise有三种状态pending(进行中)、fulfilled(已成功)和rejected(已失败)。
promise被调用后最先是处于pending状态的,只有手动调用promise构造函数中回调方法的resolve或reject才能够改变promise的状态,否则这个promise将一直处于pending状态。
二、定义初始结构
明白了这个,我们就可以开始写自己的promise了。我们平时用promise时是要通过new来创建实例的:
const promise = new Promise(() => {});
那我们的promise可以用class来进行定义
//自己手写的promise
class MyPromise {}
然后我们知道,我们在用promise的时候要给promise传一个构造函数,并且这个构造函数要传两个参数,一般叫resolve和reject。可以通过这两个参数来决定promise的最终状态。
const promise = new Promise((resolve,reject) => {});
所以我们的promise要有一个构造器去接收这个构造函数和参数,我们可以这样写:
//自己手写的promise
class MyPromise {
constructor(executor) {
executor(resolve,reject);
}
}
三、实现resolve和reject方法
但是这样写有一个明显的问题是,构造器中的resolve和reject我们没有进行定义,如果在我们手写的promise中执行resolve()或reject()不知道执行哪里的resolve和reject,所以我们得在我们手写的promise中加多两个方法。别忘了,在class中我们是需要用this来调用自身的方法的,所以我们在构造器中加上this关键字。
//自己手写的promise
class MyPromise {
constructor(executor) {
executor(this.resolve,this.reject);
}
resolve(){}
reject(){}
}
1、管理状态
然后就是promise有三种状态,初始化的promise是处于pending状态的,pending状态可以转为fulfilled和rejected状态。而且promise的状态的一但被改变就不可在更改,所以我们可以用一个变量来保存promise的状态。代码可以这样写。
//自己手写的promise
class MyPromise {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.promiseState = MyPromise.PENDING; //promise初始为pending状态
executor(this.resolve,this.reject);
}
resolve(){}
reject(){}
}
当执行resolve()或reject()的时候promise的状态就从pending转为fulfilled或rejected,且状态只能改变一次。所以我们可以通过判断promise此时的状态是否为pending来决定promise的状态是否能进行改变。
class MyPromise {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.promiseState = MyPromise.PENDING; //promise初始为pending状态
executor(this.resolve,this.reject);
}
resolve(){
if(this.promiseState !== MyPromise.PENDING ) return;
this.promiseState = MyPromise.FULFILLED;
}
reject(){
if(this.promiseState !== MyPromise.PENDING ) return;
this.promiseState = MyPromise.REJECTED;
}
}
2、保存值
在我们平时用promise的时候,在调用resolve和reject的时候是可以传参的,那我们的resolve和reject方法需要接收传过来的参数,并且把他保存到promise实例中,这样能保证每一个promise都有一个最终的值。
class MyPromise {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.promiseState = MyPromise.PENDING; //promise初始为pending状态
this.promiseValue = null;
executor(this.resolve,this.reject);
}
resolve(value){
if(this.promiseState !== MyPromise.PENDING ) return;
this.promiseValue = value;
this.promiseState = MyPromise.FULFILLED;
}
reject(reason){
if(this.promiseState !== MyPromise.PENDING ) return;
this.promiseValue = reason;
this.promiseState = MyPromise.REJECTED;
}
}
3、this指向问题
但是这样写会有问题,当我们执行如下代码的时候
const promise = new MyPromise((resolve,reject) => {
resolve();
});
会出现一个错误
为什么会出现这个错误呢?在class中的this默认指向类的实例。但是如果将某个方法单独拿出来调用,此时的this就是Undefined,因为class内部是默认严格模式,不会指向window对象。一般解决这个问题可以通过箭头函数或者bind和proxy进行解决,在这里我就用箭头函数。所以我们的代码变成了下面这个样子。
class MyPromise {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.promiseState = MyPromise.PENDING; //promise初始为pending状态
this.promiseValue = null;
executor(this.resolve,this.reject);
}
resolve = (value) => {
if(this.promiseState !== MyPromise.PENDING ) return;
this.promiseValue = value;
this.promiseState = MyPromise.FULFILLED;
}
reject = (reason) => {
if(this.promiseState !== MyPromise.PENDING ) return;
this.promiseValue = reason;
this.promiseState = MyPromise.REJECTED;
}
}
四、实现then方法
1、状态不可变
接下来再来看看then方法,在then方法中我们可以传两个回调函数,第一个是处理成功状态的回调,第二个是处理拒绝状态的回调。promise的状态从上面的代码中我们可以知道,当调用了resolve()状态变为成功状态,调用了reject()状态变为拒绝状态,且这种状态的改变只能发生一次。所以执行then方法的时候,此时的promise的状态是已经知道的了。所以代码可以这么写。
class MyPromise {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.promiseState = MyPromise.PENDING; //promise初始为pending状态
this.promiseValue = null;
executor(this.resolve,this.reject);
}
resolve = (value) => {
if(this.promiseState !== MyPromise.PENDING ) return;
this.promiseValue = value;
this.promiseState = MyPromise.FULFILLED;
}
reject = (reason) => {
if(this.promiseState !== MyPromise.PENDING ) return;
this.promiseValue = reason;
this.promiseState = MyPromise.REJECTED;
}
+ then = (onfulfilled,onrejected) => {
+ //如果是成功状态,执行第一个回调函数
+ if(this.promiseState === MyPromise.FULFILLED){
+ onfulfilled(this.promiseValue);
+ }
+ //如果是失败状态,执行第二个回调函数
+ if(this.promiseState === MyPromise.REJECTED){
+ onrejected(this.promiseValue);
+ }
}
}
//测试代码
const promise = new MyPromise((resolve,reject) => {
resolve('成功状态');
reject('失败状态');
});
promise.then(
resolve => {
console.log(resolve);
},
reject => {
console.log(reject);
}
);
执行上面的测试代码,我们查看下控制台
成功状态被输出,失败状态没有输出,说明我们此时的promise是正确的。
2、异常捕获
但是如果我们的测试代码变成下面这个样子
const promise = new MyPromise((resolve,reject) => {
throw new Error('出错了');
});
虽然这里有错误并且将其抛了出去,在我们自己手写的promise中,我们并没有对这里的错误进行处理。所以最终显示结果会如下所示,未捕获异常
Uncaught 未捕获
我们可以在执行resolve()和reject()之前用try/catch进行判断,在构造函数 constructor里面完善代码,判断生成实例的时候是否有报错
- 如果没有报错的话,就按照正常执行resolve()和reject()方法
- 如果报错的话,就把错误信息传入给reject()方法,并且直接执行reject()方法
class MyPromise {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.promiseState = MyPromise.PENDING; //promise初始为pending状态
this.promiseValue = null;
+ try {
+ executor(this.resolve,this.reject);
+ } catch (error) {
+ this.reject(error);
+ }
}
resolve = (value) => {
if(this.promiseState !== MyPromise.PENDING ) return;
this.promiseValue = value;
this.promiseState = MyPromise.FULFILLED;
}
reject = (reason) => {
if(this.promiseState !== MyPromise.PENDING ) return;
this.promiseValue = reason;
this.promiseState = MyPromise.REJECTED;
}
then = (onfulfilled,onrejected) => {
//如果是成功状态,执行第一个回调函数
if(this.promiseState === MyPromise.FULFILLED){
onfulfilled(this.promiseValue);
}
//如果是失败状态,执行第二个回调函数
if(this.promiseState === MyPromise.REJECTED){
onrejected(this.promiseValue);
}
}
}
3、then方法传参问题
在原生Promise里then方法里面的两个参数如果不是函数的话也是能够正常运行的。我们在原生代码这里不传入函数作为参数而是传入null,具体例子如下:
const promise = new Promise((resolve,reject) => {
resolve('成功');
});
promise.then(
null,
reject => {
console.log(reject);
}
);
我们发现他是可以正常执行的。
但是如果在我们自己手写的promise中,不传入函数作为参数:
const promise = new MyPromise((resolve,reject) => {
resolve('成功');
});
promise.then(
null,
reject => {
console.log(reject);
}
);
我们发现他在控制台中会报 Uncaught TypeError: onfulfilled is not a function的错误。说onfulfilled不是一个function
这显然不是我们想要的,我们可以判断传过来的参数是否为函数,如果不是函数我们就把他包装成一个函数就可以了。我们的代码可以这样子写:
class MyPromise {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.promiseState = MyPromise.PENDING; //promise初始为pending状态
this.promiseValue = null;
try {
executor(this.resolve,this.reject);
} catch (error) {
this.reject(error);
}
}
resolve = (value) => {
if(this.promiseState !== MyPromise.PENDING ) return;
this.promiseValue = value;
this.promiseState = MyPromise.FULFILLED;
}
reject = (reason) => {
if(this.promiseState !== MyPromise.PENDING ) return;
this.promiseValue = reason;
this.promiseState = MyPromise.REJECTED;
}
then = (onfulfilled,onrejected) => {
+ //如果onfulfilled不是函数,将其封装成一个函数
+ if(typeof onfulfilled !== 'function') onfulfilled = () => {};
+ //如果onrejected不是函数,抛出一个错误
+ if(typeof onfulfilled !== 'function') onrejected = () => {throw Error(this.promiseValue)};
//如果是成功状态,执行第一个回调函数
if(this.promiseState === MyPromise.FULFILLED){
onfulfilled(this.promiseValue);
}
//如果是失败状态,执行第二个回调函数
if(this.promiseState === MyPromise.REJECTED){
onrejected(this.promiseValue);
}
}
}
五、实现异步
1、出现的问题
经过这样的修改,我们的then方法就基本大功告成了,但我们手写得promise还是有一些问题的,比如用原生的promise执行下面的例子:
console.log(1);
const promise = new Promise((resolve,reject) => {
console.log(2);
resolve('resolve');
});
promise.then(
resolve => {
console.log(resolve);
}
);
console.log(3);
输出顺序为
1
2
3
resolve
但是如果用我们自己写的promise去执行这段代码,输出顺序就会变为
1
2
resolve
3
2、用setTimeout解决问题
两者输出的顺序不对,原因其实很简单,因为promise中then方法里面的代码是属于微任务,也就是console.log(resolve);这段代码是微任务,其他的都是属于同步任务,在一个宏任务中,是先执行完所有的同步任务后再去执行微任务的。而我们自己写的promise没有去设置微任务,所以导致输出顺序不同。在这里我们用setTimeout来代替微任务。我们可以在then函数中进行设置。
class MyPromise {
...
then = (onfulfilled,onrejected) => {
//如果onfulfilled不是函数,将其封装成一个函数
if(typeof onfulfilled !== 'function') onfulfilled = () => {};
//如果onrejected不是函数,抛出一个错误
if(typeof onfulfilled !== 'function') onrejected = () => {throw Error(this.promiseValue)};
//如果是成功状态,执行第一个回调函数
if(this.promiseState === MyPromise.FULFILLED){
+ setTimeout(() => {
onfulfilled(this.promiseValue);
+ })
}
//如果是失败状态,执行第二个回调函数
if(this.promiseState === MyPromise.REJECTED){
+ setTimeout(() => {
onrejected(this.promiseValue);
+ })
}
}
}
将代码改成这样子再去执行上面的测试例子,我们就发现输出顺序就跟原生的promise的输出顺序是一样的了。
3、回调保存
这样看来我们的then方法似乎差不多了,但是还是有问题的,我们看下面原生的promise的测试例子。
const promise = new Promise((resolve,reject) => {
setTimeout(() => {
resolve('测试例子');
},1000)
});
promise.then(
resolve => {
console.log(resolve);
}
);
我们发现在控制台中测试例子会在一秒后成功输出,但是如果把原生的promise换成我们自己写的promise就会发现在控制台中不会输出测试例子。这是为什么呢?这是因为我们设置了setTimeout,当执行到then方法的时候,此时的promise还没有去执行**resolve('测试例子')**去改变promise的状态,此时的promise依然是pending状态的,所以在我们写的then方法中既没有去执行成功状态的回调也没有去执行拒绝状态的回调。
因为此时的promise的状态还没有进行改变,我们需要等promise的状态改变后再去执行then里面的函数,等resolve执行了以后,再执行then
为了保留then里的函数,我们可以创建 数组 来 保存函数。
为什么用 数组 来保存这些回调呢?因为一个promise实例可能会多次 then,也就是经典的 链式调用,而且数组是先入先出的顺序
在实例化promise的时候,我们就可以创建个数组:
- promiseCallbacks:用来保存回调
class MyPromise {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
+ promiseCallbacks = [];//用来保存回调
constructor(executor) {
this.promiseState = MyPromise.PENDING; //promise初始为pending状态
this.promiseValue = null;
try {
executor(this.resolve,this.reject);
} catch (error) {
this.reject(error);
}
}
}
接下来我们就是改善下then方法
class MyPromise {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
promiseCallbacks = [];//用来保存回调
constructor(executor) {
this.promiseState = MyPromise.PENDING; //promise初始为pending状态
this.promiseValue = null;
try {
executor(this.resolve,this.reject);
} catch (error) {
this.reject(error);
}
}
then = (onfulfilled,onrejected) => {
//如果onfulfilled不是函数,将其封装成一个函数
if(typeof onfulfilled !== 'function') onfulfilled = () => {};
//如果onrejected不是函数,抛出一个错误
if(typeof onfulfilled !== 'function') onrejected = () => {throw Error(this.promiseValue)};
//如果是pending状态的,将回调函数保存在数组中
+ if(this.promiseState === MyPromise.PENDING) {
+ this.promiseCallbacks.push({onfulfilled,onrejected});
+ }
//如果是成功状态,执行第一个回调函数
if(this.promiseState === MyPromise.FULFILLED){
setTimeout(() => {
onfulfilled(this.promiseValue);
})
}
//如果是失败状态,执行第二个回调函数
if(this.promiseState === MyPromise.REJECTED){
setTimeout(() => {
onrejected(this.promiseValue);
})
}
}
}
接下来我们要完善下resolve和reject方法了,在执行resolve或reject方法时判断promiseCallbacks里有没有值,如果有值遍历执行
class MyPromise {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
promiseCallbacks = [];//用来保存回调
constructor(executor) {
this.promiseState = MyPromise.PENDING; //promise初始为pending状态
this.promiseValue = null;
try {
executor(this.resolve,this.reject);
} catch (error) {
this.reject(error);
}
}
resolve = (value) => {
if(this.promiseState !== MyPromise.PENDING ) return;
this.promiseValue = value;
this.promiseState = MyPromise.FULFILLED;
+ this.promiseCallbacks.forEach(callback => {
+ callback.onfulfilled(value)
+ });
}
reject = (reason) => {
if(this.promiseState !== MyPromise.PENDING ) return;
this.promiseValue = reason;
this.promiseState = MyPromise.REJECTED;
+ this.promiseCallbacks.forEach(callback => {
+ callback.onrejected(reason)
+ });
}
then = (onfulfilled,onrejected) => {
//如果onfulfilled不是函数,将其封装成一个函数
if(typeof onfulfilled !== 'function') onfulfilled = () => {};
//如果onrejected不是函数,抛出一个错误
if(typeof onfulfilled !== 'function') onrejected = () => {throw Error(this.promiseValue)};
//如果是pending状态的,将回调函数保存在数组中
if(this.promiseState === MyPromise.PENDING) {
this.promiseCallbacks.push({onfulfilled,onrejected});
}
//如果是成功状态,执行第一个回调函数
if(this.promiseState === MyPromise.FULFILLED){
setTimeout(() => {
onfulfilled(this.promiseValue);
})
}
//如果是失败状态,执行第二个回调函数
if(this.promiseState === MyPromise.REJECTED){
setTimeout(() => {
onrejected(this.promiseValue);
})
}
}
}
完善之后,我们在执行上面的例子,就发现测试例子在一秒后成功输出了,证明我们的代码没有问题
还有一个细节问题我们是需要知道的,比如执行下面的例子。
const promise = new Promise((resolve,reject) => {
setTimeout(() => {
resolve('测试例子');
console.log(4444);
},1000)
});
promise.then(
resolve => {
console.log(resolve);
}
);
在原生的Promise中是先输入4444在输出测试例子,而在我们自己写的promise中确实反过来的。这是什么原因呢?之前也分析过这个原因,因为then方法里面的代码是异步中的微任务,而console.log(4444)这段代码是同步任务来的,同步任务要优先异步任务执行。所以为了实现这个,我们在resolve和reject方法中加setTimeout就可以了。
class MyPromise {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
promiseCallbacks = [];//用来保存回调
constructor(executor) {
this.promiseState = MyPromise.PENDING; //promise初始为pending状态
this.promiseValue = null;
try {
executor(this.resolve,this.reject);
} catch (error) {
this.reject(error);
}
}
resolve = (value) => {
if(this.promiseState !== MyPromise.PENDING ) return;
setTimeout(() => {
this.promiseValue = value;
this.promiseState = MyPromise.FULFILLED;
this.promiseCallbacks.forEach(callback => {
callback.onfulfilled(value)
});
})
}
reject = (reason) => {
if(this.promiseState !== MyPromise.PENDING ) return;
setTimeout(() => {
this.promiseValue = reason;
this.promiseState = MyPromise.REJECTED;
this.promiseCallbacks.forEach(callback => {
callback.onrejected(reason)
});
})
}
}
经过这样子的改造之后,我们的promise跟原生的输出的顺序就是一样的了。
六、链式调用
我们知道,promise还有一个很重要的特性就是链式调用,可以解决回调地狱的问题。那么链式调用是怎么实现的呢?我们运行下面的代码:
const promise = new Promise((resolve,reject) => {
resolve();
}).then();
console.log(promise);
我们看到在控制台上输出的是一个promise的实例,也就是说then方法也会返回一个promise,这个promise也有then方法,那当然就可以实现链式调用了。
那我们自己写的promise该怎么实现这段代码呢?看下面:
then = (onfulfilled,onrejected) => {
//如果onfulfilled不是函数,将其封装成一个函数
if(typeof onfulfilled !== 'function') onfulfilled = () => {};
//如果onrejected不是函数,抛出一个错误
if(typeof onfulfilled !== 'function') onrejected = () => {throw Error(this.promiseValue)};
return new MyPromise((resolve,reject) => {
//如果是pending状态的,将回调函数保存在数组中
if(this.promiseState === MyPromise.PENDING) {
this.promiseCallbacks.push({onfulfilled,onrejected});
}
//如果是成功状态,执行第一个回调函数
if(this.promiseState === MyPromise.FULFILLED){
setTimeout(() => {
onfulfilled(this.promiseValue);
})
}
//如果是失败状态,执行第二个回调函数
if(this.promiseState === MyPromise.REJECTED){
setTimeout(() => {
onrejected(this.promiseValue);
})
}
})
}
如果resolve或reject方法返回一个值的,则执行下面的过程。如果resolve或reject方法返回一个值,我们需要在MyPromise类外部定义一个方法来处理Promise的解决过程。这个函数我们稍后进行补充。
class MyPromise {
...
then = (onfulfilled,onrejected) => {
//如果onfulfilled不是函数,将其封装成一个函数
if(typeof onfulfilled !== 'function') onfulfilled = () => {};
//如果onrejected不是函数,抛出一个错误
if(typeof onfulfilled !== 'function') onrejected = () => {throw Error(this.promiseValue)};
const thenPrommise = new MyPromise((resolve,reject) => {
//如果是pending状态的,将回调函数保存在数组中
if(this.promiseState === MyPromise.PENDING) {
this.promiseCallbacks.push({onfulfilled:() => {
+ const cb = onfulfilled(this.promiseValue);
+ resolvePromise(thenPrommise,cb,resolve,reject);
},onrejected:() => {
+ const cb = onrejected(this.promiseValue);
+ resolvePromise(thenPrommise,cb,resolve,reject);
}});
}
//如果是成功状态,执行第一个回调函数
if(this.promiseState === MyPromise.FULFILLED){
setTimeout(() => {
+ const cb = onfulfilled(this.promiseValue);
+ resolvePromise(thenPrommise,cb,resolve,reject);
})
}
//如果是失败状态,执行第二个回调函数
if(this.promiseState === MyPromise.REJECTED){
setTimeout(() => {
+ const cb = onrejected(this.promiseValue);
+ resolvePromise(thenPrommise,cb,resolve,reject);
})
}
})
return thenPrommise;
}
}
+ //用来处理Promise解决过程的函数
+ function resolvePromise(thenPrommise, cb, resolve, reject) {}
还有一个地方需要注意的是如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 thenPromise 必须拒绝执行,并返回拒因 e
class MyPromise {
...
then = (onfulfilled,onrejected) => {
//如果onfulfilled不是函数,将其封装成一个函数
if(typeof onfulfilled !== 'function') onfulfilled = () => {};
//如果onrejected不是函数,抛出一个错误
if(typeof onfulfilled !== 'function') onrejected = () => {throw Error(this.promiseValue)};
const thenPrommise = new MyPromise((resolve,reject) => {
//如果是pending状态的,将回调函数保存在数组中
if(this.promiseState === MyPromise.PENDING) {
this.promiseCallbacks.push({onfulfilled:() => {
try {
+ const cb = onfulfilled(this.promiseValue);
+ resolvePromise(thenPrommise,cb,resolve,reject);
+ }catch(e) {
+ reject(e);
+ }
},onrejected:() => {
+ try {
+ const cb = onrejected(this.promiseValue);
+ resolvePromise(thenPrommise,cb,resolve,reject);
+ }catch(e) {
+ reject(e);
+ }
}});
}
//如果是成功状态,执行第一个回调函数
if(this.promiseState === MyPromise.FULFILLED){
setTimeout(() => {
try {
+ const cb = onfulfilled(this.promiseValue);
+ resolvePromise(thenPrommise,cb,resolve,reject);
+ }catch(e) {
+ reject(e);
}
})
}
//如果是失败状态,执行第二个回调函数
if(this.promiseState === MyPromise.REJECTED){
setTimeout(() => {
+ try {
+ const cb = onrejected(this.promiseValue);
+ resolvePromise(thenPrommise,cb,resolve,reject);
+ } catch(e) {
+ reject(e);
}
})
}
})
return thenPrommise;
}
}
//用来处理Promise解决过程的函数
function resolvePromise(thenPrommise, cb, resolve, reject) {}
这样一来,我们的then方法就大功告成了。
七、resolvePromise函数的实现
接下来我们看看resolvePromise函数的实现,具体的看下面的代码。
//如果返回的值和promise2是同一个对象,则直接报错
function resolvePromise(promise2, x, resolve, reject) {
if (x === promise2) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 如果 x 为 Promise ,则使 promise2 接受 x 的状态
if (x instanceof myPromise) {
if (x.PromiseState === myPromise.PENDING) {
/**
* 如果 x 处于等待态, promise 需保持为等待态直至 x 被执行或拒绝
* 注意"直至 x 被执行或拒绝"这句话,
* 这句话的意思是:x 被执行x,如果执行的时候拿到一个y,还要继续解析y
*/
x.then(y => {
resolvePromise(promise2, y, resolve, reject)
}, reject);
} else if (x.PromiseState === myPromise.FULFILLED) {
// 如果 x 处于执行态,用相同的值执行 promise
resolve(x.PromiseResult);
} else if (x.PromiseState === myPromise.REJECTED) {
// 如果 x 处于拒绝态,用相同的据因拒绝 promise
reject(x.PromiseResult);
}
+ } else if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))) {
+ // 如果 x 为对象或函数
+ try {
+ // 把 x.then 赋值给 then
+ var then = x.then;
+ } catch (e) {
+ // 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
+ return reject(e);
+ }
+
+ /**
+ *
+ * 如果 then 是函数,将 x 作为函数的作用域 this 调用之。
+ * 传递两个回调函数作为参数,
+ * 第一个参数叫做 `resolvePromise` ,第二个参数叫做 `rejectPromise`
+ */
+ if (typeof then === 'function') {
+ // 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
+ let called = false; // 避免多次调用
+ try {
+ then.call(
+ x,
+ // 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
+ y => {
+ if (called) return;
+ called = true;
+ resolvePromise(promise2, y, resolve, reject);
+ },
+ // 2.3.3.3.2 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
+ r => {
+ if (called) return;
+ called = true;
+ reject(r);
+ }
+ )
+ } catch (e) {
+ /**
+ * 如果调用 then 方法抛出了异常 e
+ * 如果 resolvePromise 或 rejectPromise 已经被调用,则忽略之
+ */
+ if (called) return;
+ called = true;
+
+ /**
+ * 否则以 e 为据因拒绝 promise
+ */
+ reject(e);
+ }
+ } else {
+ // 如果 then 不是函数,以 x 为参数执行 promise
+ resolve(x);
+ }
+ } else {
+ // 如果 x 不为对象或者函数,以 x 为参数执行 promise
+ return resolve(x);
+ }
}
八、总结
经过层层努力,一个我们自己写的promise就写好了。当然,promise中还有很多其他的方法,比如catch、finally、all方法等,这些方法我们有机会会继续将其完善的。