在我刚刚接触Promise的时候,我一直想不通promise究竟是如何实现的,ta是怎么执行的?,Promise的链式和jq的链式一样吗?你是不是和我一样的困惑呢?那就和本文一起实现一个简单的promise吧,然后你就明白了!
在实现之前,先讲一下现实生活中的例子: 周六早上,小明的妈妈开始做饭,妈妈需要炒n个菜,可是没盐了,于是就让小明去买盐,小明的妈妈是一个很懂得利用时间的人,她是不会等着小明的,在小明买盐期间,妈妈还在炒菜,给菜都放进盘子里,一会小明回来了,妈妈直接将盐放进去了,你看中间是不是一点时间都没有浪费啊!Promise也是一样,从上到下一直走着,到resolve(小明回来了),存放回调函数的队列开始顺序执行(就好像妈妈拿着盐依次倒入每个菜盘)
先来一个基本的promise
看代码:
// executor是立即执行的 而then里面的onFullFilled, onRejected是先存起来形成一个队列,
// 等到resolve,或者reject之后执行
class Promise{
constructor(executor){
// 默认是等待状态
this.status = 'pending';
this.value = undefined;
this.reason = undefined;
// 存放成功的回调
this.onResolvedCallbacks = [];
// 存放失败的回调
this.onRejectedCallbacks = [];
// resolve或者reject的时候 执行所有callback
let resolve = (data) => {
if (this.status === 'pending') {
this.value = data;
this.status = 'resolved';
this.onResolvedCallbacks.forEach(fn => fn())
}
}
let reject = (reason) => {
this.reason = reason;
this.status = 'rejected';
this.onRejectedCallbacks.forEach(fn => fn())
}
try { // 执行时可能会发生异常
executor(resolve, reject);
} catch (e) {
reject(e); // promise失败了
}
}
// 此处的then方法主要是1,给所有的异步回调存起来
then(onFulFilled, onRejected) {
// 前两个判断是同步 用的
if (this.status === 'resolved'){
// 存放成功的回调
this.onResolvedCallbacks.push(() => {
onFulFilled(this.value);
});
this.onResolvedCallbacks.forEach(fn => fn())
}else if (this.status === 'rejected') {
// 存放失败的回调
this.onRejectedCallbacks.push(() => {
onRejected(this.reason);
});
this.onRejectedCallbacks.forEach(fn => fn())
}else{
// 存放成功的回调
this.onResolvedCallbacks.push(() => {
onFulFilled(this.value);
});
// 存放失败的回调
this.onRejectedCallbacks.push(() => {
onRejected(this.reason);
});
}
}
}
module.exports = Promise;
复制代码
new Promise((resovle,reject) => {})这个时候是立即执行executor,理解的话你可以直接看作executor();有标志的状态status,有存放回调函数的数组,等等这些属性, 在promise的原型上有一个then方法, 同步的时候(假设都是成功的话): 在执行器里面直接resolve(data) 这时候then还没执行也就是说此时执行的循环回调函数数组是空的,所以在下面的then里面我们看到又去循环执行了一遍
if (this.status === 'resolved'){
// 存放成功的回调
this.onResolvedCallbacks.push(() => {
onFulFilled(this.value);
});
this.onResolvedCallbacks.forEach(fn => fn())
}
复制代码
在异步的时候: 这个then方法就做了一件事 就是将then里面的回调函数放到了一个数组队列里面, 当promise实例resolve的时候,依次执行该实例onResolvedCallbacks数组里面的回调,失败的时候也是如此。 这样就了解了promise实现的基本原理了。知道promise究竟是怎么执行的了。
再进一步来实现Promise的链式调用
我们知道jq的链式调用时返回了当前对象,所以可以链式调用,那Promise可以吗?显然不能,我们在上一篇文章就说过,一个promise的状态一旦转变就不可逆转,所以这个链式调用绝不是返回了当前对象,事实上是在内部重新new了一个promise,作为中转来处理各种情况,看代码实现:
function resolvePromise(x, resolve, reject){
if(promise2 === x){ //x表示then成功的返回值,
console.log('循环引用')
return reject('不能自己引用自己')
}
// 判断x是不是promise
if (x !==null && (typeof x === 'object' || typeof x === 'function')){
let called;
// try一下防止取then的时候出现异常
try {
let then = x.then;
if(typeof then === 'function'){ //这里我们假设x有then方法,那么x就是promise
then.call(x, y => { //执行x身上的then方法
if(called) return;
called = true;
resolvePromise(y,resolve,reject);
}, r => {
if (called) return;
called = true;
reject(r);
})
}
} catch (e) {
}
} else {
resolve(x); // x就是一个普通值
}
}
// exccutor是立即执行的 而then里面的onFullFilled, onRejected是先存起来形成一个队列,
// 等到resolve,或者reject之后执行(只考虑异步的情况)
class Promise{
constructor(executor){
// 默认是等待状态
this.status = 'pending';
this.value = undefined;
this.reason = undefined;
// 存放成功的回调
this.onResolvedCallbacks = [];
// 存放失败的回调
this.onRejectedCallbacks = [];
// resolve或者reject的时候 执行所有callback
let resolve = (data) => {
if (this.status === 'pending') {
this.value = data;
this.status = 'resolved';
this.onResolvedCallbacks.forEach(fn => fn())
}
}
let reject = (reason) => {
this.reason = reason;
this.status = 'rejected';
this.onRejectedCallbacks.forEach(fn => fn())
}
try { // 执行时可能会发生异常
executor(resolve, reject);
} catch (e) {
reject(e); // promise失败了
}
}
// 此处的then方法主要是1,给所有的异步回调存起来
then(onFulFilled, onRejected) {
let promise2;
if (this.status === 'resolved'){
// 存放成功的回调
promise2 = new Promise((resolve, reject) => {
this.onResolvedCallbacks.push(() => {
let x = onFulFilled(this.value)
resolvePromise(x, resolve, reject)
});
})
}else if (this.status === 'rejected') {
// 存放失败的回调
promise2 = new Promise((resolve, reject) => {
this.onRejectedCallbacks.push(() => {
let x = onFulFilled(this.value)
resolvePromise(x, resolve, reject)
});
})
}else{
// 存放成功的回调
promise2 = new Promise((resolve, reject) => {
this.onResolvedCallbacks.push(() => { //resolve的时候触发执行这个
let x = onFulFilled(this.value)
resolvePromise(x, resolve, reject)
})
})
// 存放失败的回调
this.onRejectedCallbacks.push(() => {
onRejected(this.reason);
});
}
return promise2
}
}
module.exports = Promise;
复制代码
promise2就是在内部重新new的,如果上一个then的回调函数的返回值是普通值,那么就直接被promise2 resolve(普通值),如果上一个then返回的是一个promise,那么当前的这个then就会被绑定执行,这里的data当然就是返回的promise resolve的值
if(typeof then === 'function'){ //这里我们假设x有then方法,那么x就是promise
then.call(x, y => { //执行x身上的then方法
if(called) return;
called = true;
resolvePromise(promise2,y,resolve,reject);
}, r => {
if (called) return;
called = true;
reject(r);
})
}
复制代码
这就是上一篇文章所说的:
then的传递,如果then里面的回调返回的是一个Promise,那么就将这个Promise的resolve的值传递给下一个then的data值,如果返回的是一个普通值,那么就将这个普通值传递给下一个then的data值。
怎么样,对promise有更深刻的理解没?当然这篇promise的实现肯定会存在很多不足的地方,欢迎各位提出宝贵的意见或建议,也希望能帮助到你从中获得一些知识!下一篇我们来说说generator+co库和目前最流行的async await的使用以及注意事项!