一----promise理解

对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);
            })
            }
            }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值