我们先定义一个Promise 类。
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
let resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
}
}
let reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECT;
this.reason = reason;
}
}
try {
executor(resolve, reject)
//直接执行excutor并传入resolve和reject方法。
} catch (err) {
reject(err)
}
}
}
我们来分析一下,首先executor(执行器)是什么呢?
let promise = new Promise((res,rej) => {
res('成功了');
})
那么这个时候executor就是:
(res,rej) => {
res('成功了');
}
之后在这个构造函数中又定义了status(状态默认PENDING)、成功状态数据:value(默认undefined)、失败状态的原因:reason(默认undefined)、以及resolve、reject方法,最后通过try直接执行。
可以看到给excutor传入了resolve,reject方法。
那么上面写的:
(res,rej) => {
res('成功了');
}
中的res,rej就是定义在构造函数上的方法。执行res('成功了'),相当于执行:
let resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
}
}
并传入‘成功了’为value的实参。
我们再加上then方法,
then(onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
}
if (this.status === REJECTED) {
onRejected(this.reason)
}
}
}
注意:这里的then不是constructor里面的,而是原型上的。
不过这样写有一个问题。
let promise = new Promise((res, rej) => {
setTimeout(() => {
res('成功了')
}, 1000);
}).then(res => {
console.log(res)
})//ReferenceError: PENDING is not defined
这样写会报错,这是为什么呢?
因为setTimeout是异步操作,所以会先执行then,而这个时候由于还没执行resolve或reject方法,status仍为PENDING状态,所以会报错。
那我们改一下代码。
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
this.onResolvedCallbacks.forEach(fn => fn());
}
}
let reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECT;
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try {
executor(resolve, reject)
//直接执行excutor并传入resolve和reject方法。
} catch (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
}
if (this.status === REJECTED) {
onRejected(this.reason)
}
if (this.status === PENDING) {
this.onResolvedCallbacks.push(() => {
onFulfilled(this.value)
});
this.onRejectedCallbacks.push(() => {
onRejected(this.reason);
})
}
}
}
then方法接受两个参数,我们给then方法执行的的这两个参数(也是方法)传入this.value以及this.reason。并将这两个方法分别保存onResolvedCallbacks和onRejectedCallbacks中。但定时器进入回调队列并且主线程任务执行完以后,调用resolve或reject方法,
let resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
this.onResolvedCallbacks.forEach(fn => fn());
}
}
let reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECT;
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
}
}
可以看出来在调用onResolvedCallbacks或onRejectedCallbacks函数以前,就已经赋值了this.value和this.reason。
let promise = new Promise((res, rej) => {
setTimeout(() => {
res('成功了')
}, 1000);
}).then(res => {
console.log(res)
})//成功了
1秒后打印成功了。
哎呀,那这里为啥子要用forEach遍历整个数组呢?因为,要知道,Promise使用then方法后会返回一个Promise对象。而这样,就说明一个Promise可以调用多次then方法,那每个then方法中如果都使用到异步,那么forEach就显得很有用了。后面再举个例子哈。
我们知道then方法是可以不传参数的,那我们怎么进行数据的传递呢?
另外,
let promise = new Promise((res,rej) => {
res(10);
});
let test = promise.then(res => {
return test//TypeError: Chaining cycle detected for promise #<Promise>
})
这种当then的返回值与本身相同的时候,怎么解决?
先改一下then方法。
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v=>v;
onRejected = typeof onRejected === 'function' ? onRejected : err => {
throw err
};//通过这两行代码解决then方法不传入参数的问题。
let promise2 = new Promise((res, rej) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, res, rej)
} catch (e) {
reject(e)
}
}, 0);
}
if (this.status === REJECT) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, res, rej)
} catch (e) {
reject(e)
}
}, 0);
}
if (this.status === PENDING) {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, res, rej)
} catch (e) {
reject(e)
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.value);
resolvePromise(promise2, x, res, rej)
} catch (e) {
reject(e)
}
}, 0);
})
}
});
return promise2
}
}
resolvePromise(promise2, x, res, rej)方法用于解决单then的返回值与本身相同的问题,以及其他返回值问题例如,返回简单数据类型,function,其他的promise,而其他的promise中又有promise等问题。
前面也说了定时器是异步的,三个if中都借用异步,为的是先返回promise2,在执行定时器里的代码,不这么用,promise2都还没执行完呢。
那么这样就简单了,promise2是then的返回值,x可以使任意值。
再来定义resolvePromise
//这是定义在全局作用域中的
const resolvePromise = (promise2, x, resolve, reject) => {
// 自己等待自己完成是错误的实现,用一个类型错误,结束掉
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
let called;
// 后续的条件要严格判断 保证代码能和别的库一起使用
if ((typeof x === 'object' && x != null) || typeof x === 'function') {
try {
let then = x.then;
if (typeof then === 'function') {
then.call(x, y => { // 根据 promise 的状态决定是成功还是失败
if (called) return;
called = true;
// 递归解析的过程(因为可能 promise 中还有 promise) Promise/A+ 2.3.3.3.1
resolvePromise(promise2, y, resolve, reject);
}, r => {
// 只要失败就失败 Promise/A+ 2.3.3.3.2
if (called) return;
called = true;
reject(r);
});
} else {
// 如果 x.then 是个普通值就直接返回 resolve 作为结果 Promise/A+ 2.3.3.4
resolve(x);
}
} catch (e) {
// Promise/A+ 2.3.3.2
if (called) return;
called = true;
reject(e)
}
} else {
// 如果 x 是个普通值就直接返回 resolve 作为结果 Promise/A+ 2.3.4
resolve(x)
}
}
一步一步来,
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
这一步就是解决then return 自己的时候的问题。
后面的代码就有长了,首先判断是不是复杂(引用数据类型),
if ((typeof x === 'object' && x != null) || typeof x === 'function')
不是的话就说明是简单数据类型,直接就:
else {
// 如果 x 是个普通值就直接返回 resolve 作为结果
resolve(x)
}
再判断这个复杂类型有没有then方法
if (typeof then === 'function')
结果为true的话就说明这个x是Promise对象,否则就是简单数据类型,直接resolve
else {
// 如果 x.then 是个普通值就直接返回 resolve 作为结果
resolve(x);
}
而最中间的代码,
then.call(x, y => { // 根据 promise 的状态决定是成功还是失败
if (called) return;
called = true;
// 递归解析的过程(因为可能 promise 中还有 promise) Promise/A+ 2.3.3.3.1
resolvePromise(promise2, y, resolve, reject);
}, r => {
// 只要失败就失败 Promise/A+ 2.3.3.3.2
if (called) return;
called = true;
reject(r);
});
就像注释的那样。
而之前说的为什么要遍历onResolvedCallbacks或onRejectedCallbacks是因为,我可能异步操作promise中的reject或resolve,并在后面调用then方法,而在这个then方法中return出来一个新的Promise,再次借助定时器使得这个promise状态也为PENDING以此类推。
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
reject('失败');
}, 1000)
}).then(null, err => {
return new Promise((res, rej) => {
setTimeout(() => {
console.log(err);
rej('失败1');
}, 2000)
})
}).then(null, err => {
return new Promise((res, rej) => {
setTimeout(() => {
console.log(err);
rej('失败2');
}, 3000)
})
}).then(data => {
console.log(data);
}, err => {
console.log('err', err);
})
而现在的整个代码为:
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
const resolvePromise = (promise2, x, resolve, reject) => {
// 自己等待自己完成是错误的实现,用一个类型错误,结束掉 promise Promise/A+ 2.3.1
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
// Promise/A+ 2.3.3.3.3 只能调用一次
let called;
// 后续的条件要严格判断 保证代码能和别的库一起使用
if ((typeof x === 'object' && x != null) || typeof x === 'function') {
try {
// 为了判断 resolve 过的就不用再 reject 了(比如 reject 和 resolve 同时调用的时候) Promise/A+ 2.3.3.1
let then = x.then;
if (typeof then === 'function') {
// 不要写成 x.then,直接 then.call 就可以了 因为 x.then 会再次取值,Object.defineProperty Promise/A+ 2.3.3.3
then.call(x, y => { // 根据 promise 的状态决定是成功还是失败
if (called) return;
called = true;
// 递归解析的过程(因为可能 promise 中还有 promise) Promise/A+ 2.3.3.3.1
resolvePromise(promise2, y, resolve, reject);
}, r => {
// 只要失败就失败 Promise/A+ 2.3.3.3.2
if (called) return;
called = true;
reject(r);
});
} else {
// 如果 x.then 是个普通值就直接返回 resolve 作为结果 Promise/A+ 2.3.3.4
resolve(x);
}
} catch (e) {
// Promise/A+ 2.3.3.2
if (called) return;
called = true;
reject(e)
}
} else {
// 如果 x 是个普通值就直接返回 resolve 作为结果 Promise/A+ 2.3.4
resolve(x)
}
}
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
this.onResolvedCallbacks.forEach(fn => fn());
}
}
let reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
//解决 onFufilled,onRejected 没有传值的问题
//Promise/A+ 2.2.1 / Promise/A+ 2.2.5 / Promise/A+ 2.2.7.3 / Promise/A+ 2.2.7.4
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
//因为错误的值要让后面访问到,所以这里也要跑出个错误,不然会在之后 then 的 resolve 中捕获
onRejected = typeof onRejected === 'function' ? onRejected : err => {
throw err
};
// 每次调用 then 都返回一个新的 promise Promise/A+ 2.2.7
let promise2 = new Promise((resolve, reject) => {
if (this.status === FULFILLED) {
//Promise/A+ 2.2.2
//Promise/A+ 2.2.4 --- setTimeout
setTimeout(() => {
try {
//Promise/A+ 2.2.7.1
let x = onFulfilled(this.value);
// x可能是一个proimise
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
//Promise/A+ 2.2.7.2
reject(e)
}
}, 0);
}
if (this.status === REJECTED) {
//Promise/A+ 2.2.3
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0);
}
if (this.status === PENDING) {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0);
});
}
});
return promise2;
}
}