Promise实现的基石就是,先了解Promises/A+规范,我按照自己的理解简单描述下。
Promise规范
术语:
- 解决(fulfill):指一个 promise 成功时进行的一系列操作,如状态的改变、回调的执行。虽然规范中用 fulfill 来表示解决,但在后世的 promise 实现多以 resolve 来指代之。
- 拒绝(reject):指一个 promise 失败时进行的一系列操作。
- 终值(eventual value):所谓终值,指的是 promise 被解决时传递给解决回调的值,由于 promise 有一次性的特征,因此当这个值被传递时,标志着 promise 等待态的结束,故称之终值,有时也直接简称为值(value)。
- 拒因(reason):也就是拒绝原因,指在 promise 被拒绝时传递给拒绝回调的值。
要求
Promise 的状态
必须为下列三种:等待态(Pending)执行态(Fulfilled)拒绝态(Rejected)。
Pending可变为Fulfilled、Rejected,Fulfilled和Rejected是最终的状态,不能再改变,分别拥有对应的终值或拒因。
Then方法
promise.then(onFulfilled:function, onRejected?:function):Promise
需要执行onFulfilled或onRejected,如果不是函数,直接传给下一个Promise执行。
返回:
执行onFulfilled或onRejected有返回值x:
- x存在,直接执行[[Resolve]](promise2, x)
- x不存在,直接执行[[Resolve]](promise2, undefined)
- 报错error,直接执行[[Reject]](promise2, error)(规范里没说错误处理,和Promise解决过程应该是差不多的)
Promise解决过程([[Resolve]](promise, x))
如果 x 有 then 方法且看上去像一个 Promise ,解决程序即尝试使 promise 接受 x 的状态;否则其用 x 的值来执行 promise 。
x 与 promise 相等:
如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise
x 为 Promise,promise 接受 x 的状态 :
- 如果 x 处于等待态, promise 需保持为等待态直至 x 被执行或拒绝
- 如果 x 处于执行态,用相同的值执行 promise
- 如果 x 处于拒绝态,用相同的据因拒绝 promise
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链的执行过程大致如下:
- Promise1执行resolve(1), 把结果(终值, 状态)传给下一链的Promise2,和Promise3;
- Promise2是先注册的,先执行,这里状态是Fulfilled,执行成功回调函数,ok返回了一个Promise6,就直接把Promise2._next赋给返回的Promise6,由它通知下一链更新;
- Promise3,执行成功回调函数,抛出错误error,把结果(拒因, 状态)传给下一链的Promise5;
- Promise5执行失败回调函数;
- Promise6成功执行, 把结果(终值, 状态)传给下一链的Promise4,通知它更新。
代码
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");
});
转载:https://blog.csdn.net/from_the_star/article/details/106481702