promise规范
promise states
promise有三种状态:pending 准备状态 resolve 成功 reject 失败
1 .pending
初始状态,一个promise再未被resolve和reject之前的状态都是该状态 ,该状态可以转变成fulfilled 或者rejected
- fulfilled 最终的不可变的状态 通过调用resolve实现 resolve中的回调必须拥有一个value的值(也就是then中必须有一个带有参数的回调)
3.rejected
最终的不可变的状态 通过调用reject实现 reject中的回调必须拥有一个reason的值(也就是catch中必须有一个带有参数的回调或者then的第二个方法——一个带有参数的回调函数)
then
promise应该提供一个then方法, 用来访问最终的结果, 无论是value还是reason.
promise.then(onFulfilled,onRejected)
1.参数要求
then中的两个参数都必须是函数类型 如果不是函数类型的参数则忽略 程序默认传参是函数类型 并且返回值是对应的value 或者reason
- onFulfilled
在promise变成fulfilled的时候,应该调用onFulfilled 参数为value 在fulfilled之前则不能进行调用 只能执行一次
- onRejected
在promise变成onRejected的时候,应该调用onRejected 参数为reason 在rejected之前则不能进行调用 只能执行一次
4 onFulfilled和onRejected应该都是微任务
用queueMicrotask(callback)实现
5 then方法可以被调用多次 运用数组存储onFulfilled和onRejected 适用于一下场景
promise.then(fn)
promise.then(fn)
promise.then(fn)
promise.then(fn)
promise.then(fn)
6.then返回的应该是一个promise对象 用于链式调用
promise2 = promise1.then(onFulfilled, onRejected);
onFulfilled或者onRejected的执行结果我们暂且定义为x,调用resolvePromise()如果onFulfilled或者onRejected执行异常我们通过reject抛出 如果不是函数 我们需要取promise1 中的值(value或者reason) 传递给下次链式调用的触发函数 value->fulfilled reson->rejected
7 resolvePromise
resolvePromise作用:判断onFulfilled或者onRejected回调函数的类型和结果
7.1 如果x===promise2 则reject(new Error('同实例报错'))
7.2 如果 x 是一个promise的话 我们则需要继续调用x的then方法 将返回的值传入resolvePromise中 层层解刨 直到 x是一个基本类型
7.3 如果是一个object或者函数的话 let then = x.then. 如果 x.then 这步出错,那么reject掉 如果是一个函数的话then.call(x, resolvePromiseFn, rejectPromise) resolvePromiseFn 的 入参是 y, 执行 resolvePromise(promise2, y, resolve, reject); rejectPromise 的 入参是 r, reject(r). 如果 resolvePromise 和 rejectPromise 都调用了,那么第一个调用优先,后面的调用忽略。 如果调用then抛出异常e 如果 resolvePromise 或 rejectPromise 已经被调用,那么忽略 则,reject(error)
7.4 基本数据类型的话则resolve(x)
resolvePromise(promise2, x, resolve, reject)
实现
///手写promise
//定义promise中的三种状态
const PENDING='pending'
const FULFILLED= 'fulfilled'
const REJECTED='rejected'
//重新设置一个status 的意义在于我们在status改变的时候去进行数组方法的执行,这样做的好处就是保证了我们的
//reject和resolve的函数只执行一种行为,遵循函数单一原则
class JKQPromise{
FULFILLED_CALLBACK_LIST=[]
REJECTED_CALLBACK_LIST=[]
_status=PENDING
constructor(fn){
//初始默认值
this.status=PENDING
this.value=null
this.reason=null
//执行fn的方法 指定this的指向
try{
fn(this.resolve.bind(this),this.reject.bind(this))
}catch(e){
this.reject(e)
}
}
get status(){
return this._status //如果这里直接用this.status的话则直接造成死循环
}
set status(newStatus){
this._status=newStatus
//在改变状态的时候我们去执行回调数组中的方法
switch(this.status){
case FULFILLED:
this.FULFILLED_CALLBACK_LIST.forEach(callback=>{callback(this.value)})
break;
case REJECTED:
this.REJECTED_CALLBACK_LIST.forEach(callback=>{callback(this.reason)})
break;
}
}
//修改promise中的状态
//resolve
resolve(value){
console.log(value,'3331ss')
if(this.status===PENDING){
this.status=FULFILLED
this.value=value
}
}
//reject
reject(reason){
if(this.status===PENDING){
this.status=REJECTED
this.reason=reason
}
}
//then方法 两个回调 成功的回调和失败的回调
then(onFulfilled,OnRejected){
//判断回调的方法类型 如果不是函数则应该被忽略 执行内部的默认 直接将ressolve中的value返回 实现穿透
let realFulfilled=this.isFunction(onFulfilled)?onFulfilled:value=>value
let realRejected=this.isFunction(OnRejected)?OnRejected:reason=>reason
//链式调用的原因 then方法返回的仍然是一个promise对象(新的)
let promise2 = new JKQPromise((resolve,reject)=>{
//将传入进来的回调函数放在数组中便于状态改变的时候统一执行
///在链式调用的时候如果上一个promise执行错误 则下一个then就获取不到
let fulfilledMicrotask=()=>{
queueMicrotask(()=>{
try{
//resolve执行后的返回值
let x= realFulfilled(this.value)
this.resolvePromise(promise2,x,resolve,reject)
}catch(e){
//如果错误抛出错误
reject(e)
}
})
}
let rejectedMicrotask=()=>{
queueMicrotask(()=>{
try{
const x = realRejected(this.reason)
this.resolvePromise(promise2,x,resolve,reject)
}catch(e){
reject(e)
}
})
}
switch(this.status){
case FULFILLED:
fulfilledMicrotask()
break;
case REJECTED:
rejectedMicrotask()
break;
case PENDING:
//将成功或者失败状态下的回调函数添加到 对应的回调数组中
this.FULFILLED_CALLBACK_LIST.push(onFulfilled)
this.REJECTED_CALLBACK_LIST.push(OnRejected)
break
}
})
//返回promise对象 实现链式调用
return promise2
}
// 对于回调x进行判断和处理
resolvePromise(promise2,x,resolve,reject){
if(promise2===x){
///证明是实例和返回的对象是一个东西则返回错误
return reject(new Error('the same object'))
}
if(x instanceof JKQPromise){
console.log(x)
//如果是promise的实例的话 则继续重复调用 对于调用中获取到的值 在进行继续解析
queueMicrotask(()=>{
x.then((y)=>{
///通过循环调用的方式获取最后的基本类型的数据(详情看测试) 用于下一个链式调用
this.resolvePromise(promise2,y,resolve,reject)
},reject)
})
}else if(typeof x === 'object' || this.isFunction(x)){
//空对象
if(x === null){
return resolve(x)
}
let then = null
try {
// 把 x.then 赋值给 then
then = x.then;
} catch (error) {
// 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
return reject(error);
}
///如果对象或者函数中存在then 并且then是个函数
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(e){
if(called) return
//执行报错 则直接reject掉
reject(e)
}
}else{
//不是函数则直接执行resolve
resolve(x)
}
}else{
//直接执行resovle
resolve(x)
}
}
catch(OnRejected){
//返回的是then的调用
return this.then(null,OnRejected)
}
isFunction(params){
return typeof params ==='function'
}
//resolve 的直接调用
static resolve(value){
if(value instanceof JKQPromise){
//如果value 是promise的实例的话 直接返回 实现链式调用
return value
}else{
new JKQPromise((resolve,reject)=>{
resolve(value)
})
}
}
static reject(reason) {
return new MPromise((resolve, reject) => {
reject(reason);
});
static all(arrays){
return new MPromise((resolve,reject)=>{
if(!Array.isArray(arrays)){
throw new Error('不是数组')
}
let length =arrays.length
let resolveArray=[]
for(let i =0;i< length;i++){
arrays[i].then(data=>{
resolveArray.push(data)
if(length==resolveArray.length){
//resove出去 外面通过then可以全部获取
resolve(resolveArray)
}
},reject)
}
})
}
}
}
总结: 1.then方法返回的是一个新的promise 这个promise的初始状态是pending
2.当第一promise中的onFulfilled不是函数的时候其resolve的value或默认的传递给新创建的promise 以便于一下then使用 也就是说上一个then中的值会作为下一个then中的回调函数的参数使用(上一个promise then得返回才能使用)
3.resolvePromise(promise2,x,resolve,reject)就是对于传入x参数进行类型的判断,根据类型的不同执行逻辑不同 如果x是promise2实例 则reject(error) 如果是 JKQPromise的实例的话 则递归调用直到获取到 直到resolve出去为止 如果是object或者function的时候 内部有then方法且为函数的时候 调用then方法then.call(x,(y)=>{ //继续对y进行类型判断 直到resolve出去为止 this.resolvePromise(promise2, y, resolve, reject); }, (r) => {reject(r); })
- 链式调用 then中都返回的是新的promise对象 当第一个promise中执行resolve后 通过then可以获取到第一个resolve的值 then 返回的新的promise 会根据then的回调函数的返回值 去执行内部的类型判断 然后在决定当前promise的状态和值 5.链式调用用catch后边继续链式then的话then也可以执行 因为 catch进行了异常的处理,返回的也是promise对象 并且后面then中的value使用的是catch之前的值,注意:在链式调用中catch回调函数 如果抛出异常则状态是rejected 如果正常执行则状态是fulfilled reason被后续的catch所继续使用