对promise有一些理解以此记录:
1、promise A+规范要求有三个状态,分别是pending,fulfilled,rejected。promise实例初始化时是pending状态。实例初始化时会把new promise传入的方法马上执行。
class myPromise{
resolveList = [];
rejectList = [];
_status = null;
constructor(fn){
this.status = 'pending';
this.value = null;
this.reason = null;
try{
fn(this.resolve.bind(this),this.reject.bind(this))
}catch(e){
this.reject(e);
}
}
2、它有几个方法:
resolve方法触发使promise状态变化,这时要注意状态是单向改变的,只能从pending转变为fulfilled;
resolve(value){
if(this.status=='pending'){
this.value = value;
this.status = 'fulfilled';
}
}
reject方法触发使promise状态变化,这时要注意状态是单向改变的,只能从pending转变为rejected;
reject(reason){
if(this.status=='pending'){
this.reason = reason;
this.status = 'rejected';
}
}
then方法有两个参数(onFulfilled,onRjected)返回一个新的promise实例,若我们写一个promise实例,后面有写then方法,那么它在promise实例化之后马上会被调用执行,这个方法里主要处理不同状态不同的执行方法,但若是异步状态下,即在调用then时状态还未改变,那么需要用一个数组来把then的回调方法存起来,之所以用数组是因为它是一个可按顺序存储多个数据的结构,因为一个promise实例可能连续执行多次then方法,这个时候用数组可以保证顺序执行回调。执行回调时需要用微任务,回调返回一个x,这个x未知所以需要用resolvepromise方法去解析。
isFunction(fn){
return typeof fn ==='function';
}
then(onFulfilled,onRjected){
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
return value
}
const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {
throw reason;
};
const promise2 = new myPromise((resolve,reject)=>{
const queueFulfilledFn = ()=>{
queueMicrotask(()=>{
try{
const x = realOnFulfilled(this.value);
this.resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
})
}
const queueRejectedFn = ()=>{
queueMicrotask(()=>{
try{
const x = realOnRejected(this.reason);
this.resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
})
}
switch(this.status){
case 'pending':{
this.resolveList.push(queueFulfilledFn);
this.rejectList.push(queueRejectedFn);
}
break;
case 'fulfilled':queueFulfilledFn() break;
case 'rejected':queueRejectedFn(); break;
})
return promise2;
}
resolvePromise方法是解析then的回调方法返回值的,它可能有多种情况,比如then返回的还是promise实例就需要循环解析这样才能一层一层解析让后面调用的then链按顺序执行。
resolvePromise(promise2,x,resolve,reject){
if(promise2 === x){
return reject(new TypeError('the promise and the return value are the same'))
if(x instanceof myPromise){
queueMicrotask(()=>{
x.then((y)=>{
this.resolvePromise(promise2,y,resolve,reject);
},reject)
})
}else if(isFunction(x)||typeof x ==='object'){
if(x ==null){
return resolve(x);
}
let then = null;
try{then = x.then}catch(e){
return reject(e)
}
if(isFunction(then)){
let called = false;
try{
then.call((y)=>{
if(called){return;}
called = true;
this.resolvePromise(promise2,y,rsolve,reject)
},(r)=>{
if(called){return}
called = true;
reject(r)
})
}catch(e){
if(called){
return;
}
reject(e)
}
}
}else{
resolve(x);
}
}
设置一个status的get/set方法,这样能监听status的变化,它一变化需要去处理数组里的回调。
get status(){
return this._status;
}
set status(newStatus){
this._status = newStatus;
switch (newStatus){
case 'fulfilled':this.resolveList.forEach((callback)=>{callback(this.value)});break;
case 'rejected':this.rejectList.forEach((callback)=>{
callback(this.reason);
});break;
}
}
catch方法
catch(onRejected){
return this.then(null,onRejected);
}
finally 方法
finally (callback) {
return this.then(value => {
// 如果是promise就把它在解析一遍向下传递。为了兼容使用MyPromise.resolve(callback())
return MyPromise.resolve(callback()).then(() => value)
}, reason => {
return MyPromise.resolve(callback()).then(() => {throw reason})
})
}
静态方法
//返回一个转变成功状态的promise实例
static resolve(value){
if(value instanceof myPromise){
return value;
}
return new myPromise((resolve)=>{
resolve(value);
})
}
//返回一个转变失败状态的peomise实例
static reject(value){
if(value instanceof myPromise){
return value;
}
return new myPromise((resolve)=>{
reject(value);
})
}
//竞速,谁先转变状态就先返回谁
static race(promiseList){
return new myPromise((resolve,reject)=>{
if(promiseList.length>0){
return resolve();
}
for(let i=0;i<promiseList.length;i++){
myPromise.resolve(promiseList[i]).then(
(res)=>{return resolve(res)},
(reason)=>{return reject(reason)}
)
}
})
}
//使用快的Promise,“中断”慢的Promise,其实也不是中断,只是不采纳慢的Promise的结果
//比如有个请求要10s返回,结果,我等不及了,2秒后我就要“中断”他
const promise1 = new myPromise((resolve, reject)=> {
setTimeout(()=> {
resolve('OK 成功了');
}, 10000)
})
// 把上面的promise1传入到wrap函数的race中
const wrap = promise=> {
let abort;
const p1 = new myPromise((resolve, reject)=> {
abort = reject;
})
// 思路:提前reject p1,那么race采纳的就是p1的结果
const p2 = myPromise.race([promise, p1]);
p2.abort = abort;
return p2;
}
const wrapPromise = wrap(promise1);
wrapPromise.then(
data=> {
console.log('success', data)
},
err=> {
console.log('failed', err); // failed 超时!
}
)
console.log(wrapPromise);
setTimeout(()=> {
wrapPromise.abort('超时!');
}, 2000)
例子:
const test = new myPromise((resolve,reject)=>{
settTimeout(()=>{
resolve(111);
},1000)
}).then(()=>{
console.log(test);
//这位置test打印出来的status为pending,value为null,因为test是then返回的新的promise这个回调执行时,这个新的promise的状态还没改变,要等他执行完毕才能改变。
})
setTimeout(()=>{
console.log(test);
//这个位置打印的testvalue为undefined、status为fulfilled,如上所说,这个新的promise执行完毕之后因为then的回调执行完毕使得新的promise的状态改变resolve了,但是返回的值为undefined,即x为undefined,所以value为undefined。
},2000)
如:
//promise实例初始化,会把then全部执行了,这时若是异步的,状态未改变,那么会把回调函数全部存储在数组里,等resolve状态改变在执行回调。
new myPromise((resolve,reject)=>{
setTimeout(()=>{
resolve(111);
},1000)
//promise1
}).then(()=>{//promise1.then,返回promise2
//这个回调依赖promise1的resolve执行,即promise1状态变化为成功,它执行完之后执行resolvepromise然后执行resolve,这个resolve其实是promise2的resolve
}).then(()=>{//promise2.then,返回promise3
//前面的then调用成功后即promise2的状态改变了,会执行这个回调,这个回调会执行resolvepromise,resolvepromise里执行resolve,这个resolve是promise3的
}).catch(()=>{//promise3.then,返回promise4
//前面promise3resolve被执行则状态改变执行这个回调。
})
3、最后记录一个promise问题
//宏任务开始执行Promise.resolve().then,then里的回调作为微任务进入微任务队列
Promise.resolve().then(() => {
console.log(0);
setTimeout(() => {
console.log('宏任务');
}, 0);
return Promise.resolve(4);//会产生两个微任务。只有等待当前栈为空时才会resolve掉这个新的promise让x.then()的回调入栈,这也就2这个回调比它先入栈的原因(因为0这个回调执行后理论上要把新的promise4x.then这个解析回调推入,但是它需要等当前栈空才能推入,所以等到1取出来执行结束才算空,但是1执行的时候又将2推入栈中,所以2先于x.then回调入栈),接着2执行完了让3入栈,这个新的promise的x.then回调执行完了在让4入栈,所以4在3后面打印,后面的以此类推
//若这里不是return promise 是return 4,则结果是0,1,4,2,3,5,6,7,8
}).then((res) => {
console.log(res);
});
//这个宏任务Promise.resolve().then执行结束,then后的回调方法进入微任务对列,
//直到这个主线程宏任务结束才会执行微任务队列
Promise.resolve().then(() => {
console.log(1);
}).then(() => {
console.log(2);
}).then(() => {
console.log(3);
}).then(() => {
console.log(5);
}).then(() => {
console.log(6);
}).then(() => {
console.log(7);
}).then(() => {
console.log(8);
})
//原生的结果是:0,1,2,3,4,5,6,7,8,宏任务
若是想在js实现的promise上保持和原生一致,则需要在返回为promise实例的情况家手动加一层微任务
resolvePromise(promise2, x, resolve, reject) {
// 如果 newPromise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 newPromise
// 这是为了防止死循环
if (promise2 === x) {
return reject(new TypeError('The promise and the return value are the same'));
}
if (x instanceof MPromise) {
// 如果 x 为 Promise ,则使 newPromise 接受 x 的状态
// 也就是继续执行x,如果执行的时候拿到一个y,还要继续解析y
queueMicrotask(() => {//这里加了一层微任务使得和原生输出一致
x.then((y) => {
this.resolvePromise(promise2, y, resolve, reject);
}, reject);
})
}
}