PromiseA+规范解读&手写MyPromsie
Promise 是什么?
promise 对象 订阅异步回调,在处理异步函数时,如发请求,让你能够把异步操作最终的成功返回值或者失败原因和相应的处理程序关联起来。这样使得异步方法可以像同步方法那样返回值,使代码更加整洁。ES6 新增内容,和 async await 配合使用效果更加
const promise1= new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('foo')
},300)
})
promise1.then(res=>{
console.log(res) // foo
})
- promise 是一个有then 方法的对象或者函数,行为遵循本规范。
- value ,promise 状态成功时的值,resolve的参数,类型:number boolean undefined,promise等
- reason ,promise状态 失败的值,reject的参数,表示各种拒绝的原因
- exception 异常值
有三种状态
- Pending
1.1 初始的状态,可变化
1.2 resolve:pending=>fulfilled 状态
1.3reject:pending=>rejected 状态 - fulfilled
2.1最终态,不可变
2.2一个promise 被resolve后会变成这个状态
2.3必须拥有一个value的值
const promise1= new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve()
},300)
})
promise1.then(res=>{
console.log(res) // undefined
})
- rejected
3.1 最终状态,不可变
3.2一个promise 被reject 后会变成这个状态
3.3必须拥有一个reason 值
then
promise 应该提供一个then 方法,用来访问最终的结果
then 接受两个参数,onfulfilled 和 onReject,
promise.then(onfulfilled,onReject)
参数要求
- onfulfilled 必须是函数类型,如果部署函数类型,应该被 忽略
- onReject必须是函数类型,如果部署函数类型,应该被 忽略
onfulfilled 特性
- promise 变成fulfilled时,应该调用onfulfilled ,参数时 value
- promise 变成fulfilled之前,不应该被调用
- 只能被调用一次
onReject特性
- promise 变成rejected时,应该调用onReject,参数时 reason
- promise变成rejected之前,不应该被调用
- 只能被调用一次
onfulfilled 和 onReject 执行环境应该是微任务里
// 浏览器提供的使用微任务队列的方法,兼职性不好
queueMicrotask(()=>{
//异步方法放在在这里
})
then 方法可以被调用多次
const promise2 = new Promise();
promise2.then(cb1,cb2)
promise2.then(cb1,cb2)
promise2.then(cb1,cb2)
promise2.then(cb1,cb2)
promise 状态变成fulfilled 发,所有的 onFulfiled 回调按照 then 的顺序执行
promise 状态变成rejected发,所有的 rejected回调按照 then 的顺序执行
then 返回值
- then 返回值应该是一个 promise,是一个新的 promise
- onFulfilled 或者onRejected执行的结果为X,调用resolvePromise()
- onFulfilled 或者onRejected 执行的时候报错了,promise2就需要被reject
- onFulfilled 不是一个函数,promise 2 以promise 的value,触发 fulfilled
- onRejected 不是一个函数,promise2 以promise 1的reason,触发onRejected
resolvePromise
resolvePromise(promise2,x,resolve,reject)
1、promise2 ===x ,reject typeError
2、如果X是一个promise
pending \fulfilled\ rejected (需要判断三种状态)
3、object /function
let then = x.then;
then 如果是一个函数,then.call(x)=>x.then
手写Promise
// 1、初始化
//2、三种状态
// 3、设置初始状态
// 4、resolve/reject
// 1.更新status,pending->fulfilled/rejected
// 2.入参value/reason
// 5、promise 构造函数的入参 resolve reject (两个函数),任何 new Promsie 的会调用
// 6、then 入参 出参
const PENDING = 'pending'
const FULFILLED= 'fulfilled'
const REJECTED= 'rejected'
class MyPromise{
FULFILLED_CALLBACK_LIST=[]
REJECTED_CALLBACK_LIST=[]
_status =PENDING
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)
}
}
get status(){
return this._status
}
set status(newStatus){
this._status = newStatus
switch(newStatus){
case FULFILLED:
this.FULFILLED_CALLBACK_LIST.forEach(callback=>{
callback(this.value)
})
break;
case REJECTED:
this.REJECTED_CALLBACK_LIST.forEach(callback=>{
callback(this.reason)
})
break;
}
}
resolve(value){
if(this.status===PENDING){
this.value = value;
this.status = FULFILLED;
}
}
reject(reason){
if(this.status===PENDING){
this.reason= reason;
this.status = REJECTED;
}
}
then(onFulfilled,onRejected){
const realOnFulfilled = this.isFunction(onFulfilled)?onFulfilled:(value)=>{ return value}
const realOnRejected = this.isFunction(onRejected)?onRejected:(reason)=>{ return reason}
const promise2 = new MyPromise((resolve,reject)=>{
const fulfilledMicrotask =()=>{
queueMicrotask(()=>{
try{
const x = realOnFulfilled(this.value)
this.resolvePromise(promise2,x,resolve,reject)
}catch(e){
reject(e)}
})
}
const rejectedMicrotask =()=>{
queueMicrotask(()=>{
try{
const x = realOnRejected(this.reason)
this.resolvePromise(promise2,x,resolve,reject)
}catch(e){
reject(e)
}
})
}
switch(this.status){
case FULFILLED: fulfilledMicrotask(this.value); break;
case REJECTED: rejectedMicrotask(this.reason); break;
case PENDING :
this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask )
this.REJECTED_CALLBACK_LIST.push(rejectedMicrotask )
break;
}
})
return promise2
}
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(x instanceof Object||x instanceof Function){
if(x ===null){return resolve(x)}
let then = null
try {
then = x.then
}catch(error){return reject(error)}
if(this.isFunction(then)){
let called = false
try{
then.call(x,(y)=>{
if(called) return
called = true;
this.resolvePromise(promise2,y,resolve,reject)
},(r)=>{
if(called) return
called = true;
reject(r)
})
}catch(error){
if(called){
return
}
reject(error)
}
}else{
resolve(x)
}
}else{
resolve(x)
}
}
catch(onRejected){
return this.then(null,onRejected )
}
static resolve(value){
if(value instanceof MyPromise){
return value
}
return new MyPromise((resolve,reject)=>{
resolve(value)
})
}
static reject(reason){
if(reason instanceof MyPromise){
return value
}
return new MyPromise((resolve,reject)=>{
reject(reason)
})
}
isFunction(param){
return typeof param === 'function'
}
}
const test = new MyPromise((resolve,reject)=>{
setTimeout(()=>{
reject(122)
},1000)
}).then(value=>{console.log(`[then value=${value}`)},error=>{
console.log(error,'sffdsf')
})
console.log(test)
setTimeout(()=>{
console.log(test)
},2000)