js手写方法之–Promise
Promise
与async/await
是ES6中常用的异步操作方法,为了深刻理解Promise
的用法,解读源码是一个很好的方案。其核心方法是Promise
构造函数,以及.then
方法,其他静态方法都是在此基础之上封装的
为了方便理解,以下代码经过了适当删减
// Promise状态常量值
// 状态还未变化
const PENDING = 0
// 成功
const FULLFILLED = 1
// 失败
const REJECTED = 2
function MyPromise (executor) {
// 初始状态,0
this.state = PENDING
// 状态成功时的值,初始为 undefined
this.value = undefined
// 状态失败时的值,初始为 undefined
this.reason = undefined
// 异步时,成功的回调;同步任务时为空
// 也可以这么理解:
// 异步方法时,先.then将回调推入this.onResolvedCallbacks; 再resolve更改状态 并执行回调
// 同步方法时,先resolve更改状态,再.then执行回调
this.onResolvedCallbacks = []
// 异步时,失败的回调;同步任务时为空
this.onRejectedCallbacks = []
// executor 中执行resolve的方法
const resolve = (result) => {
// 状态一旦改变,就不能再改变了
if (this.state === PENDING) {
this.state = FULLFILLED
this.value = result
this.onResolvedCallbacks.forEach(cb => { cb() })
}
}
const reject = (error) => {
// 状态一旦改变,就不能再改变了
if (this.state === PENDING) {
this.state = REJECTED
this.value = error
this.onRejectedCallbacks.forEach(cb => { cb() })
}
}
try {
// excutor 是用户传来的执行器
// 即 new Promise(function(resolve, reject) {}) 中的function
// 从这里也能看出 excutor 是同步执行
excutor(resolve, reject)
} catch (e) {
reject(e)
}
}
接下来是添加原型链方法.then
// 构造器建好后,添加原型链方法
MyPromise.prototype = {
constructor: MyPromise,
// then接受两个参数,一个是成功方法,一个是失败方法
then: function (onResolved, OnRejected) {
// 如果成功方法不存在,他就是一个返回当前值的方法
onResolved = onResolved ? onResolved : result => result
// 如果失败方法不存在,他就是一个把当前信息当成错误抛出的方法
onRejected = onRejected ? onRejected : err => { throw err}
/**
* Promise支持.then().then()这种链式调用,所以then()的返回值也应是一个Promise对象
* 由于Promise存在前面的then执行成功,后面的then执行失败的情况
* 所以不能返回当前状态已经固定的this,而是返回一个新的Promise
*/
let p2 = new Promise((resolve, reject) => {
// 根据当前promise的状态判断是否执行回调
if (this.state === FULLFILLED) {
// 执行了 resolve(result),状态成功,this.value = result
let result
if (isPromise(this.value)) {
// this.value是一个Promise,那么result也是一个promise
result = this.value.then(onResolved, onRejected)
} else {
// 此时result可能是普通对象,也可能是promise
result = onResolved(this.value)
}
// 对result进行解析,直到最终执行resolve(obj)或reject(err)
// obj为result最后返回的那个对象
resolvePromise(result, resolve, reject)
}
if (this.state === REJECTED) {
// 执行了reject(error),状态失败,this.reason = error
let error
if (isPromise(this.reason)) {
error = this.reason.then(onResolved, onRejected)
} else {
error = onRejected(this.reason)
}
// 对error进行解析,直到最终执行reject(err)
resolvePromise(error, resolve, reject)
}
if (this.state === PENDING) {
// 异步方法,执行器excutor中还未执行到resolve,于是将回调推入回调数组中
this.onResolvedCallbacks.push(() => {
if (isPromise(this.value)) {
result = this.value.then(onResolved, OnRejected )
} else {
result = onResolved(this.value)
}
resolvePromise(result, resolve, reject)
})
this.onRejectedCallbacks.push(() => {
let error
if (isPromise(this.reason)) {
error= this.reason.then(onResolved, OnRejected )
} else {
error= onRejected(this.reason)
}
resolvePromise(error, resolve, reject)
})
}
})
return p2
}
}
/**
* 判断一个对象是否为Promise对象
* 判断他是否拥有then方法
*/
function isPromise (obj) {
if ((typeof obj === 'object' && obj !== null) || typeof obj === 'function') {
if (typeof obj.then === 'function') {
return true
}
}
return false
}
// 这个方法的目的,是解析result中的data
// 并最终执行外层p2的resolve或reject方法
function resolvePromise (result, resolve, reject) {
if (isPromise(result)) {
// 因为then内部新建了一个promise,所以这里需要判断result是否执行过了
let called = false
try {
let then = result.then
// 这里 then.call(result, r=>{}, j=>{})
then.call(result, r => {
if (called) return
called = true
resolvePromise(r, resolve, reject)
}, j => {
if (called) return
called = true
resolvePromise(j, resolve, reject)
})
} catch (e) {
if (called) return
called = true
reject(e)
}
} else {
// result是基本对象,直接resolve
resolve(result)
}
}
其他Promise方法
其他Promise方法都是上述的一个封装
MyPromise.prototype.catch(errorFn)
MyPromise.prototype.catch = function (errorFn) {
return this.then(null, errorFn)
}
MyPromise.resolve(data)
MyPromise.resolve = function (data) {
return new MyPromise((resolve, reject) => {
resolve(data)
})
}
MyPromise.reject(error)
MyPromise.reject= function (error) {
return new MyPromise((resolve, reject) => {
reject(error)
})
}
MyPromise.all([...promiseObj])
/**
* 所有promise执行成功后,返回整个列表
* 如果有失败的,返回最先失败的结果
*/
MyPromise.all= function (promiseObj = []) {
return new Promise((resolve, reject) => {
let result = []
// 记录总数量,每成功一次减一
let index = allPromise.length
for (let i = 0; i < promiseObj.length; i++) {
let p = promiseObj[i]
if (isPromise(p)) {
p.then(data => {
result[i] = data
// 异步成功后才减去index
index--
if (index === 0) {
resolve(result)
}
}).catch(err => {
// 任何一个异步失败都抛出错误
reject(err)
})
} else {
result[i] = p
// 非promise对象,直接减一
index--
}
}
// 如果没有异步数据
if (index === 0) {
resolve(result)
}
})
}
MyPromise.race([...promiseObj])
/**
* 谁先执行完成返回谁,不管是成功还是失败
*/
MyPromise.race = function (promiseObj= []) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promiseObj.length; i++) {
let p = promiseObj[i]
if (isPromise(p)) {
p.then(resolve).catch(reject)
} else {
resolve(p)
}
}
})
}