js:Promise源码实现(function、原型)

参考: https://juejin.cn/post/7047492676190634021#comment
https://juejin.cn/post/7102708871763853348

1、前置知识:

(1)promise的基本知识

  • 作用:异步处理;解决“回调地狱”,提高可读性
  • 三种状态:pending、resolved(也叫fulfilled)、rejected(后两种状态只能从pending转换过来,不存在resolved、rejected互转)

实例方法:

  • then:会返回一个promise对象;参数是两个回调函数,resolved、rejected状态对应的执行函数
  • catch:相当于then中的第二个函数
  • all:一个promise对象数组,全部执行成功则返回一个状态为resolved的promise对象;否则rejected
  • race:一个promise对象数组,返回第一个完成的promise对象,无论是resolved还是rejected

(2)原型

MyPromise类的原型上写方法,实例p可以继承

2、Promise实现

(1)构造函数

function MyPromise(executor) {
    
    
    this.status = 'pending'
    this.result = null

    // 箭头函数不会改变this指向,this仍然指向当前的promise对象,而不是指向resolve函数
    const resolve = (data) => {
    
    
        if(this.status !== 'pending')
            return
        
        this.status = 'resolved'
        this.result = data
        
        // 队列思想,先进先出;
        // 1、执行then方法时,为pending状态的每个promise对象保存一对回调函数;
        // 2、等到状态变为resolved时,从队列中取出暂存的回调函数,顺序调用
        while(this.onResolvedCallbacks.length > 0) {
    
    
            this.onResolvedCallbacks.shift()()  // 调用
            this.onRejectedCallbacks.shift()
        }
    }

    const reject = (data) => {
    
    
        if(this.status !== 'pending')
            return
        
        this.status = 'rejected'
        this.result = data
        
        while(this.onRejectedCallbacks.length > 0) {
    
    
            this.onResolvedCallbacks.shift()
            this.onRejectedCallbacks.shift()()  // 调用
        }
    }

    // 把写好的resolve、reject作为MyPromise构造函数的两个参数
    executor(resolve, reject)
}

关于executor(resolve, reject)的理解:

① 先看promise对象的创建形式:

// 箭头函数就对应了上面代码中的executor
let p1 = new MyPromise((resolve, rejct)=>{
    
    
	// 函数体
	// 需要显式调用resolve、reject函数,修改promise状态
	resolve('ok')
})

② resolve、reject
这两个函数,是我们在MyPromise中事先写好的,使用executor(resolve, reject),分配给MyPromise构造函数的两个对应参数

改成以下形式也是一样的效果,因为这里是形参:

let p1 = new MyPromise((success, failed)=>{
 success(‘ok’)
})

然后,在函数体中调用时,才会执行相应的函数代码

③ executor的作用
将实例的参数名(回调函数名)跟MyPromise类中的resolve、reject对应起来

(2)then、catch方法

① then返回的是一个promise对象(支持链式调用)

MyPromise.prototype.then = function (onResolved, onRejected) {
    
    
    // 如果传入参数不是函数,为其初始化为空函数
    onResolved = typeof onResolved === 'function' ? onResolved : ()=>{
    
    }
    onRejected = typeof onRejected === 'function' ? onRejected : ()=>{
    
    }

    return new MyPromise((resolve, reject) => {
    
    
        // this指向执行then方法的MyPromise实例
        if(this.status === 'resolved') {
    
    
            let res = onResolved(this.result)   // then方法的返回值
            resolve(res)    // 传递给下一个then
        }
        if(this.status === 'rejected' && onRejected) {
    
    
            let err = onRejected(this.result)
            reject(err)
        }
        // 说明前一步还没有完成,先保存两个回调,等待完成后再执行
        if(this.status === 'pending') {
    
    
            this.onResolvedCallbacks.push(()=>{
    
    
                let res = onResolved(this.result)
                resolve(res)
            })
            this.onRejectedCallbacks.push(()=>{
    
    
                let err = onRejected(this.result)
                reject(err)
            })
        }
    })
}

② catch相当于第二个参数为空函数的then方法

MyPromise.prototype.catch = function(onRejected) {
    
    
    if(this.status === 'rejected') {
    
    
        onRejected(this.result)
    }
    if(this.status === 'pending') {
    
    
        this.onResolvedCallbacks.push(()=>{
    
    
            // push一个空的回调函数,占位
        })
        this.onRejectedCallbacks.push(()=>{
    
    
            onRejected(this.result)
        })
    }
}

③ 链式调用then方法:

let p1 = new MyPromise((resolve, reject)=>{
    
    
	// resolve('ok')
    reject('error')
})
p1.then((value)=>{
    
    
    console.log('value', value)
    return value
}
,(reason)=>{
    
    
    console.log('reason:', reason)	// 执行,输出 reason:error
    return reason
}).then((res)=>{
    
    
    console.log('res:', res)
},(err)=>{
    
    
    console.log('err:', err)	// 执行,输出 err:error
    return 'catch_Error'
}).catch((err)=>{
    
    
    console.log('catch:', err)	// 执行,输出 catch:catch_Error
})

(3)all、race方法

① all:一个promise对象数组,只有当所有对象的状态都为resolved时,返回一个resolved的promise对象(由原数组的返回值组成);否则返回第一个rejected的promise对象的值

MyPromise.prototype.all = function(promiseArray) {
    
    
    const values = []
    let count = 0

    return new MyPromise((resolve, reject)=>{
    
    
        promiseArray.forEach((p, index) => {
    
    
            // 把p包装成MyPromise对象,因为可能传入的p并不是promise对象
            p = p instanceof MyPromise ? p : new MyPromise((resolve, reject) => resolve(p))
            p.then(
                (value)=>{
    
    
                    count++
                    values[index] = value   // 保持跟原数组顺序一致
                    if(count === promiseArray.length) {
    
    
                        resolve(values)
                        console.log('status:', this.status)
                    }
                },
                (err) => {
    
    
                    reject(err)
                }
            )
        })
    })
}

② race:一个promise对象数组,返回第一个执行完成的promise对象,无论成功与否

MyPromise.prototype.race = function(promiseArray) {
    
    
    return new MyPromise((resolve, reject)=>{
    
    
        promiseArray.forEach((p) => {
    
    
            p = p instanceof MyPromise ? p : new MyPromise((resolve, reject) => {
    
     resolve(p) })
            p.then(
                (value)=>{
    
    
                    resolve(value)
                },
                (err) => {
    
    
                    reject(err)
                }
            )
        })
    })
}

调用all、race方法:

let p1 = new MyPromise((resolve, reject)=>{
    
    
    resolve('p1')
})
let p2 = new MyPromise((resolve, reject)=>{
    
    
    resolve('p2')
})
let p3 = new MyPromise((resolve, reject)=>{
    
    
    resolve('p3')
})
let p4 = new MyPromise((resolve, reject)=>{
    
    
    reject('p4')
})

let P1 = new MyPromise((resolve, reject)=>{
    
    })

P1.all([p1,p2,p3]).then((res)=>{
    
    
    console.log('res:', res)
}, (err)=>{
    
    
    console.log('err:', err)

})

P1.all([p1,p2,p4]).then((res)=>{
    
    
    console.log('res:', res)
}, (err)=>{
    
    
    console.log('err:', err)

})

P1.all(['1','2','3']).then((res)=>{
    
    
    console.log('res:', res)
}, (err)=>{
    
    
    console.log('err:', err)

})

P1.race([p1,p2,p4]).then((res)=>{
    
    
    console.log('res:', res)
}, (err)=>{
    
    
    console.log('err:', err)

})

P1.race([p4,p1,p2]).then((res)=>{
    
    
    console.log('res:', res)
}, (err)=>{
    
    
    console.log('err:', err)

})

在这里插入图片描述

3、补充

catch方法、then方法中第二个函数的区别?
——catch相当于then的第二个方法,但是指下一个then,不是前一个then
——在同一个then中,第二个方法捕获不到第一个方法抛出的异常

let p = new Promise((resolve, reject)=>{
    
    
	
})
p.then(()=>{
    
    }, ()=>{
    
    })
	.catch(()=>{
    
    })
p.then(()=>{
    
    },()=>{
    
    })
	.then(()=>{
    
    }, ()=>{
    
     
		// 相当于这个方法 
	})

猜你喜欢

转载自blog.csdn.net/qq_38432089/article/details/127005766