前沿
俗话说站在前辈巨擘的肩上,才能看的更远。在拜读了巨擘大咖们写的promise实现之后,全身经络通畅,如被先辈们用金手指点中了百会穴。至此以后,运行大小周天比往常更熟练了几分。然而,肩井穴,涌泉穴,每日亥时,都会隐隐作痛。思来想去,大概时先前巨擘的文章精妙,我一时无法全部领悟其中奥妙。固苦心感悟,方得此篇。不敢与前辈比肩,只当部分补充而已
直男不懂铺垫,所以直接干
这里我们用es6来实现,这样结构比较明显,如果有对es6不太熟悉的朋友,可以看看阮一峰老师的ECMAScript 6 入门
class myPromise {
constructor(executor){
this.value = null;
this.reason = null;
const resolve = value =>{
this.value = value;
}
const reject = reason => {
this.reason = reason;
}
try {
executor(resolve,reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled,onRejected){
onFulfilled(this.value)
onRejected(this.reason)
}
}
代码解析:
- myPromise是一个构造函数,参数是一个高阶函数,接受两个内部函数resolve,reject
- myPromise的实例都可以调用then方法,then方法的第一个参数接受resolve的返回,第二个参数接受reject的返回
学武功的第一步是(自宫)对比
起手式
观察后发现:我们实现的myPormise和Promise运行的结果一致(good guy!),只是有一个小问题,我们是先调用的p1的then,但是p1的then返回却是在p2的then返回之后。我们保留疑问,继续淦!!!
resolve/reject的单一性
意思就是当一个promise中的resolve或者reject执行了之后,那之后resolve/reject都不再执行
观察之后,发现这就不对了
- 别人家的promise只返回了一个'p1-resolve',而咱们家的promise返回了'p2-resolve2'和'p2-reject1'
- 别家的promise和咱们家的promise不一样就算了,咋还少了一个'p2-resolve1'呢?这里的原因是reslove方法里面,我们用一个内部变量this.value保存了resolve的值,当执行resolve('p2-resolve1')之后,再执行resolve('p2-resolve2')时,this.value就被后者重新赋值了。然后再执行到then函数时,自然而然'p2-resolve1'就消失了。
- 怎么修改呢? 这里我们引入一个内部状态的概念来处理这个问题,初始状态我们设置为'pending',它只有一次改变状态的机会,它可以变成pending->fulfilled或者pending->rejected,一旦改变之后,就不在变化。(是不是像极了宝可梦的进化)。
- 另外为了保证resolve/reject执行的唯一性,当状态不在是pending时,resolve/reject就不执行
所以...(就决定是你了,皮卡丘!!!)
class myPromise {
constructor(executor){
+ this.state = 'pending'; //内部状态为pending,resolve,reject
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 (e) {
reject(e)
}
}
then(onFulfilled,onRejected){
+ if(this.state === 'fulfilled'){
onFulfilled(this.value)
+ }
+ if(this.state === 'rejected') {
onRejected(this.reason)
+ }
}
}
修改之后,再观察,咱们家的promise又正常了一些。
promise的异步执行
我们稍微清理一下我们的测试代码,使它看上去清爽自然
清理完之后。我们加上异步
通过观察,我们发现,我们的promise没有任何打印
- 仔细思考之后,我们可以想到,当resolve还没有执行的时候,then函数已经执行了,而这时的state为'pending',所以then函数里面不会有任何执行
- 我们怎么处理这种情况呢?首先可以想到,当resolve/reject的时候,这个时候执行then时的state为'pending',而这个时候,我们不知道之后到底时执行resolve呢?还是reject,所以我们只有将所有的then的所有的参数(onFulfilled/onRejected)都暂存起来,以待之后的state改变之后执行对应的方法(onFulfilled/onRejected)
- 当状态改变之后,立即执行暂存的对应的方法
基于上面所说,我们修改我们的promise
class myPromise {
constructor(executor){
this.state = 'pending'; //内部状态为pending,resolve,reject
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(value))
}
}
const reject = reason => {
if(this.state === 'pending'){
this.state = 'rejected';
this.reason = reason;
+ this.onRejectedCallbacks.forEach(fn=>fn(reason))
}
}
try {
executor(resolve,reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled,onRejected){
if(this.state === 'fulfilled'){
onFulfilled(this.value)
}
if(this.state === 'rejected') {
onRejected(this.reason)
}
+ if(this.state === 'pending') {
+ this.onFulfilledCallbacks.push(onFulfilled)
+ this.onRejectedCallbacks.push(onRejected)
+ }
}
}
修改之后,我们看看结果 观察之后,发现我们的promise能够正常的显示then回调了,而且还有意外收获,仔细观察我们发现,p1.then和p2.then打印的顺序和调用时的顺序一致了!!!
同步异步一致性
不论promise里面的resolve/reject是同步或者异步,我们都希望then返回的执行表现一致 我们创建一个执行对比
经过观察,我们可以发现
- 别人家的promise,不论resolve是同步的还是异步的,then返回都是异步的
- 咱们家的promise,当resolve是异步的,then返回是异步的,当resolve是同步的返回就是同步的
那么怎么改呢?我们的目的是要保持then的执行一致,所以只能把全部的then修改成异步的,原因在上一节已经说明了 我们来修改一下咱们家的promise
class myPromise {
constructor(executor) {
this.state = 'pending'; //内部状态为pending,resolve,reject
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(value))
}
}
const reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn(reason))
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
if (this.state === 'fulfilled') {
+ setTimeout(()=>{
onFulfilled(this.value)
+ })
}
if (this.state === 'rejected') {
+ setTimeout(()=>{
onRejected(this.reason)
+ })
}
if (this.state === 'pending') {
+ this.onFulfilledCallbacks.push((value)=>setTimeout(()=>{onFulfilled(value)}))
+ this.onRejectedCallbacks.push((reason)=>setTimeout(()=>{onRejected(reason)}))
}
}
}
然后来看看执行
现在咱们家的promise就更像别人家的了
为什么是数组
细心的小伙伴会发现this.onFulfilledCallbacks和this.onRejectedCallbacks是数组,在then方法里面,当state === 'pending'时,我们把onFulfilled和onRejected添加再数组进数组,而不是直接赋值给this.onFulfilledCallbacks/this.onRejectedCallbacks。会觉得这里直接赋值好像也没有什么问题。
我们修改一下我们promise直接用变量存储
class myPromise {
constructor(executor) {
this.state = "pending"; //内部状态为pending,resolve,reject
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(value));
+ this.onFulfilledCallbacks(value);
}
};
const reject = (reason) => {
if (this.state === "pending") {
this.state = "rejected";
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn(reason));
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
if (this.state === "fulfilled") {
setTimeout(() => {
onFulfilled(this.value)
})
}
if (this.state === "rejected") {
setTimeout(() => {
onRejected(this.reason)
})
}
if (this.state === "pending") {
- this.onFulfilledCallbacks.push((value)=>setTimeout(()=>{onFulfilled(value)}));
+ this.onFulfilledCallbacks = (value)=>setTimeout(()=>{onFulfilled(value)});
this.onRejectedCallbacks.push(onRejected);
}
}
}
经过观察我们发现:
- 别人家的promise,两个then回调的onFulfilled都正常执行了,咱们家的只执行了第二个then回调的
- 咱们家的promise的问题是,第二个then执行的时候,覆盖了第一个then的onFulfilledCallbacks赋值。所以这里只会执行第二个then回调的onFulfilled
我们把代码回滚到上一节,然后进入下一节
链式调用
then方法无论何时都返回一个promise实例
我们仔细观察一下
- 别人家的promise是执行了第一个then方法之后,又成功的执行了第二个then方法
- 咱们家的promise是执行了第一个then方法之后,第二个then方法就报错了
- 因为咱们家的promise的then方法没有返回一个promise对象
我们按着我们的分析来修改一下我们的promise
class myPromise {
constructor(executor) {
this.state = "pending"; //内部状态为pending,resolve,reject
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(value));
}
};
const reject = (reason) => {
if (this.state === "pending") {
this.state = "rejected";
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn(reason));
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
if (this.state === "fulfilled") {
setTimeout(() => {
onFulfilled(this.value)
})
}
if (this.state === "rejected") {
setTimeout(() => {
onRejected(this.reason)
})
}
if (this.state === "pending") {
this.onFulfilledCallbacks.push((value)=>setTimeout(()=>{onFulfilled(value)}));
this.onFulfilledCallbacks = (value)=>setTimeout(()=>{onFulfilled(value)});
}
+ return new myPromise((resolve,reject)=>{
+ resolve()
+ })
}
}
修改完成之后,我们执行看看
经过观察我们可以发现
- p2-resolve-then2已经成功的打印出来了,只是和别人家的promise打印的位置不太对
第二个then的返回值问题
第二个then的onFulfilled的参数是第一个onFuifilled的return值
所以我们修改一下我们执行代码
这里有一个小tips,这里用了并的逻辑运算符,console.log()这个函数返回一个undefined,所以在前面取了非
花开两朵各表一枝,
我们观察发现
- 别人家的promise的第二个then能够正常的接收到第一个then传递过来的值
- 咱们家的promis却不能,其实也不奇怪,咱们家的promise在then里面返回的promise中的resolve方法中没有参数!!!
我们按着这个思路,来改改咱们家的promise
class myPromise {
constructor(executor) {
this.state = "pending"; //内部状态为pending,resolve,reject
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(value));
}
};
const reject = (reason) => {
if (this.state === "pending") {
this.state = "rejected";
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn(reason));
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
const promise2 = new myPromise((resolve, reject) => {
if (this.state === "fulfilled") {
setTimeout(() => {
+ // 万一onFulfilled方法报错,我们用trycatch捕获一下
+ try {
+ let x = onFulfilled(this.value);
+ resolve(x)
+ } catch (error) {
+ reject(error)
+ }
})
}
if (this.state === "rejected") {
setTimeout(() => {
+ try {
+ let x = onRejected(this.reason);
+ //这里暂时有点问题,我们先这么写,因为这里比较符合逻辑
+ reject(x)
+ } catch (error) {
+ reject(error)
+ }
})
}
if (this.state === "pending") {
this.onFulfilledCallbacks.push(value => {
+ try {
+ let x = onFulfilled(value)
+ resolve(x)
+ } catch (error) {
+ reject(error)
+ }
});
this.onRejectedCallbacks.push(reason => {
+ try {
+ let x = onRejected(reason)
+ //这里暂时有点问题,我们先这么写,因为这里比较符合逻辑
+ reject(x)
+ } catch (error) {
+ reject(error)
+ }
});
}
})
return promise2;
}
}
最后来看看结果
观察可以返现,咱们家的promise已经和别人家的promise已经越来越像了(牛头人警告!)
then函数的onRejected的返回会被下一个then函数的onFulfilled方法接受
我们来看看例子
仔细观察我们发现
- 别人家的promise的then函数链的执行是p1-reject-then1(第一个then的onRejected)=>p1-resolve-then2(第二个then的onFulfilled)
- 咱们家的promise的then函数链的执行是p2-reject-then1(第一个then的onRejected)=>p2-reject-then2(第二个then的onRejected)
- 这里的不同是promise的reject不需要传递(这是约定,不要为我为啥)
我画了一个图
所以我们来修改咱们家的promise
class myPromise {
constructor(executor) {
this.state = "pending"; //内部状态为pending,resolve,reject
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(value));
}
};
const reject = (reason) => {
if (this.state === "pending") {
this.state = "rejected";
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn(reason));
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
const promise2 = new myPromise((resolve, reject) => {
if (this.state === "fulfilled") {
setTimeout(() => {
// 万一onFulfilled方法报错,我们用trycatch捕获一下
try {
let x = onFulfilled(this.value);
resolve(x)
} catch (error) {
reject(error)
}
})
}
if (this.state === "rejected") {
setTimeout(() => {
try {
let x = onRejected(this.reason);
- //这里暂时有点问题,我们先这么写,因为这里比较符合逻辑
- reject(x)
+ resolve(x)
} catch (error) {
reject(error)
}
})
}
if (this.state === "pending") {
this.onFulfilledCallbacks.push(value => {
try {
let x = onFulfilled(value)
resolve(x)
} catch (error) {
reject(error)
}
});
this.onRejectedCallbacks.push(reason => {
try {
let x = onRejected(reason)
- //这里暂时有点问题,我们先这么写,因为这里比较符合逻辑
- reject(x)
+ reslove(x)
} catch (error) {
reject(error)
}
});
}
})
return promise2;
}
}
修改完了,我们来看看结果
bingo!!! 咱们家的promise又像了别人家的promise几分
调整一下结构
大体上的 结构已经完成了,接下来我们要调整一下,方便接下来的对比
class myPromise {
constructor(executor) {
this.state = "pending"; //内部状态为pending,resolve,reject
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(value));
}
};
const reject = (reason) => {
if (this.state === "pending") {
this.state = "rejected";
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn(reason));
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
const promise2 = new myPromise((resolve, reject) => {
if (this.state === "fulfilled") {
setTimeout(() => {
// 万一onFulfilled方法报错,我们用trycatch捕获一下
try {
let x = onFulfilled(this.value);
- reslove(x)
+ resolvePromise(promise,x,resolve,reject)
} catch (error) {
reject(error)
}
})
}
if (this.state === "rejected") {
setTimeout(() => {
try {
let x = onRejected(this.reason);
- reslove(x)
+ resolvePromise(promise,x,resolve,reject)
} catch (error) {
reject(error)
}
})
}
if (this.state === "pending") {
this.onFulfilledCallbacks.push(value => {
try {
let x = onFulfilled(value)
- reslove(x)
+ resolvePromise(promise,x,resolve,reject)
} catch (error) {
reject(error)
}
});
this.onRejectedCallbacks.push(reason => {
try {
let x = onRejected(reason)
- reslove(x)
+ resolvePromise(promise,x,resolve,reject)
} catch (error) {
reject(error)
}
});
}
})
return promise2;
}
}
+ function resolvePromise(promise2,x,resovle,reject) {
+ resolve(x)
+ }
我们创建了一个函数resolvePromise 专门来处理resolve相关的逻辑,因为这部分高度复用,所以我们把它单独抽离成一个函数,目前这个函数里面还是只执行了resolve(x)
当onFulfilled/onRejected的返回值是一个promise对象时
观察可以发现,
- 别人家的promise正常的将promise里面的resolve值传递给了第二个then方法
- 咱们家的promise,像一个铁憨憨一下,把promise实例当一个值返回了
这里咱们要弄懂,promise链式调用,具体的实现逻辑
解析:
- 一般情况下,我们调用resolve传递的是当前then(onFulfilled,onRejected)的onFulfilled和onRejected的返回
- 当onFulfilled和onRejected的返回是一个promise实例时,resolve传递的是当前这个实例的then(onFullfilled,onRejected)中的onFullfilled/onRejected的返回
根据我们的理解,来修改咱们家的promise
class myPromise {
constructor(executor) {
this.state = "pending"; //内部状态为pending,resolve,reject
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(value));
}
};
const reject = (reason) => {
if (this.state === "pending") {
this.state = "rejected";
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn(reason));
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
const promise2 = new myPromise((resolve, reject) => {
if (this.state === "fulfilled") {
setTimeout(() => {
// 万一onFulfilled方法报错,我们用trycatch捕获一下
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
if (this.state === "rejected") {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
if (this.state === "pending") {
this.onFulfilledCallbacks.push(value => {
try {
let x = onFulfilled(value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
});
this.onRejectedCallbacks.push(reason => {
try {
let x = onRejected(reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
});
}
})
return promise2;
}
}
function resolvePromise(promise2, x, resolve, reject) {
+ if (x instanceof myPromise) {
+ if (x.state === 'pending') {
+ x.then((y) => {
+ resolvePromise(promise2, y, resolve, reject)
+ }, reject)
+ } else {
+ x.then(resolve, reject)
+ }
+ } else {
resolve(x)
+ }
}
修改了之后,我们来看看
观察以后,发现咱们家的promise也越来越标准化了
特殊中的特殊情况
当resolve返回的是一个包含then函数的对象,或者函数时,要执行一次这个then函数
首先我们来看看对比
经过观察我们可以发现,
- 别人家的promise是成功的返回了,fn1的入参
- 而咱们家的promise却吧整个对象都返回了
- 别人家的promise,调用了fn1和fn2,但是只执行了排在前面的fn1,是因为fn1和fn2和resolve/reject一样都有单一执行原则
- 小问题,如果then里面的fn1/fn2返回的是一个promise对象呢?这个问题仔细想想?
- 结论就是,我们还要按照promise的标准再一次处理一下
我们按照我们的想法来完善咱们家的promise
class myPromise {
constructor(executor) {
this.state = "pending"; //内部状态为pending,resolve,reject
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(value));
}
};
const reject = (reason) => {
if (this.state === "pending") {
this.state = "rejected";
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn(reason));
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
const promise2 = new myPromise((resolve, reject) => {
if (this.state === "fulfilled") {
setTimeout(() => {
// 万一onFulfilled方法报错,我们用trycatch捕获一下
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
if (this.state === "rejected") {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
if (this.state === "pending") {
this.onFulfilledCallbacks.push(value => {
try {
let x = onFulfilled(value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
});
this.onRejectedCallbacks.push(reason => {
try {
let x = onRejected(reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
});
}
})
return promise2;
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (x instanceof myPromise) {
if (x.state === 'pending') {
x.then((y) => {
resolvePromise(promise2, y, resolve, reject)
}, reject)
} else {
x.then(resolve, reject)
}
+ } else if(x && (typeof x === 'object'|| 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);
+ },(e)=>{
+ if(called) return;
+ called = true;
+ reject(e)
+ })
+ }else{
+ resolve(x)
+ }
+ } catch (error) {
+ if(called) return;
+ called = true;
+ reject(error)
+ }
+ }
else {
resolve(x)
}
}
修改完了之后,我们来看看结果
当然返回一个有then方法的函数结果也是一样的
可以看见咱们家的promise,又一次完成进化,现在快成长成一个独当一面的promise了
处理极端情况
then(onFulfilled,onRejected)中的onFulFilled返回的是当前的then()
我们来看看对比
观察可以发现
- 别人家的promise报错了
- 咱们家的promise没有反应
- 咱们家的promise没有反应,是因为它在无限的执行then,陷入了死循环
我们画个图
这是一个正常情况
当2这onFulfilled返回的是上面整个then时,就陷入了自我循环
所以这里,我们阻止一下自我循环
class myPromise {
...
}
function resolvePromise(promise2, x, resolve, reject) {
+ if(promise2===x) {
+ return reject(new TypeError('自我循环'))
+ }
if (x instanceof myPromise) {
...
}
}
当then(onFulfilled,onRejected)中的onFulfilled,onRejected不为function时
这里是约定,所以没有啥理由
我们来加上
then(onFulfilled, onRejected) {
+ onFulfilled = typeof onFulfilled === 'function'? onFulfilled:y=>y;
+ onRejected = typeof onRejected === 'function'? onRejected:y=>{throw y;}
let promise2 = new myPromise((resolve, reject) => {
当一个promise的reslove的参数是一个promise的时候
暂时不知道为什么,有知道的大佬说明一下 这个也是一个约定,我们来看一个例子
观察之后,可以发现,resolve的promise传递是reslove的值,而reject是直接传递promise实例 所以我们来改造咱们家的promise
const resolve = (value) => {
+ if (value instanceof myPromise) {
+ return value.then(resolve, reject)
+ }
if (this.state === "pending") {
this.state = "fulfilled";
this.value = value;
this.onFulfilledCallbacks.forEach((fn) => fn(value));
}
};
到这里,咱们家的promise,大概就是这个样子的
class myPromise {
constructor(executor) {
this.state = "pending"; //内部状态为pending,resolve,reject
this.value = null;
this.reason = null;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (value instanceof myPromise) {
return value.then(resolve, reject)
}
if (this.state === "pending") {
this.state = "fulfilled";
this.value = value;
this.onFulfilledCallbacks.forEach((fn) => fn(value));
}
};
const reject = (reason) => {
if (this.state === "pending") {
this.state = "rejected";
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn(reason));
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : y => y;
onRejected = typeof onRejected === 'function' ? onRejected : y => { throw y; }
const promise2 = new myPromise((resolve, reject) => {
if (this.state === "fulfilled") {
setTimeout(() => {
// 万一onFulfilled方法报错,我们用trycatch捕获一下
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
if (this.state === "rejected") {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
if (this.state === "pending") {
this.onFulfilledCallbacks.push(value => {
setTimeout(() => {
try {
let x = onFulfilled(value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
});
this.onRejectedCallbacks.push(reason => {
setTimeout(() => {
try {
let x = onRejected(reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
});
}
})
return promise2;
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (x === promise2) {
return new TypeError('自我循环')
}
if (x instanceof myPromise) {
if (x.state === 'pending') {
x.then((y) => {
resolvePromise(promise2, y, resolve, reject)
}, reject)
} else {
x.then(resolve, reject)
}
} else if (x && (typeof x === 'object' || 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);
}, (e) => {
if (called) return;
called = true;
reject(e)
})
} else {
resolve(x)
}
} catch (error) {
if (called) return;
called = true;
reject(error)
}
}
else {
resolve(x)
}
}
最后用promises-aplus-tests测试一下我们的promise
npm init
npm i promises-aplus-tests -D
修改一下package.json
"scripts": {
// 后面接你的文件
"test": "promises-aplus-tests ./src/index.js"
},
执行
npm run test
最后发现有40测试没通过
少年,你还记得一招从天而降的掌法吗?
这里,其他的文章会告诉这是promise的规范,就仿佛回到了小学时代,我懵懵懂懂的问老师问题时,老师告诉我只需要记住就行了。 但是,我拒绝!!!
我们来看一个极端的例子
为什么不一样的呢?
究其根本原因,resolvePromise返回了一个状态为fuifilled的promise
在promise内部的resolvePromise()方法内,直接执行了x.then(reslove,reject)
所以把custom thenable当成了值,错误的返回了
这里怎么处理呢
class myPromise {
constructor(executor) {
this.state = "pending"; //内部状态为pending,resolve,reject
this.value = null;
this.reason = null;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (value instanceof myPromise) {
return value.then(resolve, reject);
}
+ setTimeout(() => {
if (this.state === "pending") {
this.state = "fulfilled";
this.value = value;
this.onFulfilledCallbacks.forEach((fn) => fn(value));
}
+ })
};
const reject = (reason) => {
+ setTimeout(()=>{
if (this.state === "pending") {
this.state = "rejected";
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn(reason));
}
+ })
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : y => y;
onRejected = typeof onRejected === 'function' ? onRejected : y => { throw y; }
const promise2 = new myPromise((resolve, reject) => {
if (this.state === "fulfilled") {
setTimeout(() => {
// 万一onFulfilled方法报错,我们用trycatch捕获一下
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
if (this.state === "rejected") {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
if (this.state === "pending") {
this.onFulfilledCallbacks.push(value => {
- setTimeout(() => {
try {
let x = onFulfilled(value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
- })
});
this.onRejectedCallbacks.push(reason => {
- setTimeout(() => {
try {
let x = onRejected(reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
- })
});
}
})
return promise2;
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (x === promise2) {
return reject(new TypeError('自我循环'))
}
if (x instanceof myPromise) {
if (x.state === 'pending') {
x.then((y) => {
resolvePromise(promise2, y, resolve, reject)
}, reject)
} else {
x.then(resolve, reject)
}
} else if (x && (typeof x === 'object' || 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);
}, (e) => {
if (called) return;
called = true;
reject(e)
})
} else {
resolve(x)
}
} catch (error) {
if (called) return;
called = true;
reject(error)
}
}
else {
resolve(x)
}
}
我们把所有的resolve/reject都改成异步触发
最后的最后
我们执行 执行
npm run test
终于通过了全部的测试用例了
最终代码
class myPromise {
constructor(executor) {
this.state = "pending"; //内部状态为pending,resolve,reject
this.value = null;
this.reason = null;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (value instanceof myPromise) {
return value.then(resolve, reject);
}
setTimeout(() => {
if (this.state === "pending") {
this.state = "fulfilled";
this.value = value;
this.onFulfilledCallbacks.forEach((fn) => fn(value));
}
});
};
const reject = (reason) => {
setTimeout(() => {
if (this.state === "pending") {
this.state = "rejected";
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn(reason));
}
});
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (y) => y;
onRejected =
typeof onRejected === "function"
? onRejected
: (y) => {
throw y;
};
const promise2 = new myPromise((resolve, reject) => {
if (this.state === "fulfilled") {
setTimeout(() => {
// 万一onFulfilled方法报错,我们用trycatch捕获一下
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
}
if (this.state === "rejected") {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
}
if (this.state === "pending") {
this.onFulfilledCallbacks.push((value) => {
try {
let x = onFulfilled(value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
this.onRejectedCallbacks.push((reason) => {
try {
let x = onRejected(reason);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
}
});
return promise2;
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (x === promise2) {
return reject(new TypeError("自我循环"));
}
if (x instanceof myPromise) {
if (x.state === "pending") {
x.then((y) => {
resolvePromise(promise2, y, resolve, reject);
}, reject);
} else {
x.then(resolve, reject);
}
} else if (x && (typeof x === "object" || 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);
},
(e) => {
if (called) return;
called = true;
reject(e);
}
);
} else {
resolve(x);
}
} catch (error) {
if (called) return;
called = true;
reject(error);
}
} else {
resolve(x);
}
}
myPromise.deferred = function () {
let defer = {};
defer.promise = new myPromise((resolve, reject) => {
defer.resolve = resolve;
defer.reject = reject;
});
return defer;
};
module.exports = myPromise;
本文使用 mdnice 排版