Promise实现的基石就是,先了解Promises/A+规范,我按照自己的理解简单描述下。
必须为下列三种:等待态(Pending)执行态(Fulfilled)拒绝态(Rejected)。
Pending可变为Fulfilled、Rejected,Fulfilled和Rejected是最终的状态,不能再改变,分别拥有对应的终值或拒因。
promise.then(onFulfilled:function, onRejected?:function):Promise
需要执行onFulfilled或onRejected,如果不是函数,直接传给下一个Promise执行。
返回:
执行onFulfilled或onRejected有返回值x:
如果 x 有 then 方法且看上去像一个 Promise ,解决程序即尝试使 promise 接受 x 的状态;否则其用 x 的值来执行 promise 。
x 与 promise 相等:
如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise
x 为 Promise,promise 接受 x 的状态 :
x 为对象或函数:
规范里x只要有其暴露出一个遵循 Promise/A+ 协议的 then 方法,就会当作Promise处理,如果抛出异常就拒绝,这我没有实现。
如果 x 不是含有then,以 x 为参数执行 promise
我的Promise数据结构如下
class AjPromise {
private state: PENDING|FULFILLED|REJECTED = PENDING;
private _value: any; //终值
private _reason: any; //拒因
private _next: Array<AjPromise> = []; //下一链的Promise
private _ok: Function; //保存成功回调函数
private _ng: Function; //保存失败回调函数
public then(onFulfilled?: Function, onRejected?: Function) {...}
public catch(onRejected?: Function) {...}
private _fire(value,state){...}
}
我是利用类似于链表的结构实现Promise链的
Promise里中ok用来保存成功回调函数,ng用来保存失败回调函数
then函数是用来创建一个新的Promise,并给它添加ng和ok函数
catch函数也是用来创建一个新的Promise,并给它添加ng函数
这两函数创建的新Promise都要加到Promise链上去。
_next是一个数组,用来保存下一链的Promise
还有一个私有函数_fire,是用来执行回调方法,修改自身状态,并把执行结果通知给下一链(next)里的Promise门
const promise1 = new AjPromise((resolve, reject) =>{
setTimeout(()=>{
resolve(1)
},100)
});
const promise2 = promise1.then(()=>{
console.log("promise2");
return new AjPromise((resolve, reject) =>{
setTimeout(()=>{
resolve(1)
},100)
})
},()=>{})
const promise4 = promise2.then((v)=>{
console.log("promise4",v);
})
const promise3 = promise1.then((v)=>{
throw new Error("我错了");
})
const promise5 = promise3.catch((v)=>{
console.log(v);
})
构建结束后大概就是下图
构建好Promise链的执行过程大致如下:
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function isFunc(f) {
return typeof f === 'function';
}
class AjPromise {
state = PENDING;
_value;
_reason;
_next = [];
_ok;
_ng;
constructor(fn) {
if(isFunc(fn)){
const resolve = (value)=>this._fire(value,FULFILLED);
const reject = (value)=>this._fire(value,REJECTED);
try {
fn(resolve, reject);
} catch (e) {
reject(e);
}
}
}
then(onFulfilled, onRejected) {
let promise = new AjPromise();
promise._ok = onFulfilled;
promise._ng = onRejected;
this._next.push(promise);
// 如果上一个Promise已经完成,直接触发这一个Promise执行回调函数
try {
if(this.state === REJECTED){
setTimeout(()=>{promise._fire(this._reason ,REJECTED)},0);
}else if(this.state === FULFILLED){
setTimeout(()=>{promise._fire(this._value ,FULFILLED)},0);
}
} catch (error) {
setTimeout(()=>{promise._fire(error ,REJECTED)},0);
}
return promise;
}
catch(onRejected) {
let promise = new AjPromise();
promise._ng = onRejected;
this._next.push(promise);
return promise;
}
//触发执行Promise函数,并修改状态
_fire(value,state){
if(state === FULFILLED){
this._value||(this._value = value);
this.state = PromiseHandle(this,this._ok,this._value,state);
}else if(state === REJECTED){
this._reason||(this._reason = value);
this.state = PromiseHandle(this,this._ng,this._reason,REJECTED);
}
}
}
//Promise回调处理函数
function PromiseHandle (promise,handle,value,state){
let res;
if(value instanceof AjPromise){
value._fire(null,value.state);
return value.state;
}
if(isFunc(handle)){//是函数,执行
try {
if(promise.state === PENDING){
res = handle(value);
}else{ //执行过就不执行
res = this._value;
}
} catch (error) {
for (const p of promise._next) {//通知下一链失败回调
if(p instanceof AjPromise && p.state === PENDING)
setTimeout(()=>{p._fire(error,REJECTED)},0);
}
return REJECTED;
}
//对返回结果处理
if(res instanceof AjPromise){
res._next = promise._next;
}else{
for (const p of promise._next) {//通知下一链成功回调
if(p instanceof AjPromise && p.state === PENDING)
setTimeout(()=>{p._fire(res,FULFILLED)},0);
}
}
}else {//不是函数,直接传给下一链
for (const p of promise._next ) {
if(p instanceof AjPromise && p.state === PENDING){
setTimeout(()=>{p._fire(value,state)},0);
}
}
}
return FULFILLED;
};
测试代码:
这是Promise 链式调用顺序引发的思考文章里的例子,看上面的实现代码,就可以了解它的输出结果是啥了,我就不贴结果了,大家可以想一下,再对比结果。
new AjPromise((resolve, reject) => {
console.log("log: 外部promise");
resolve();
})
.then(() => {
console.log("log: 外部第一个then");
new AjPromise((resolve, reject) => {
console.log("log: 内部promise");
resolve();
})
.then(() => {
console.log("log: 内部第一个then");
})
.then(() => {
console.log("log: 内部第二个then");
});
})
.then(() => {
console.log("log: 外部第二个then");
});