promise源码实现
<script>
// 实现微任务执行
let myNextTick = (function() {
let cbCellect = []
let num = 0
function fn() {
let copy = cbCellect.slice()
cbCellect = []
copy.forEach(cb => {
cb()
})
}
let observer = new MutationObserver(fn)
let node = document.createElement('div')
observer.observe(node, {
childList: true
})
return function(cb) {
// 收集回调
cbCellect.push(cb)
num = (num + 1) % 2
// 节点改变
node.innerHTML = num
}
})()
let PENDING = 'pending'
let FULFILLED = 'fulfilled'
let REJECTED = 'rejected'
class MyPromise {
// Promise.resolve()
static resolve(val) {
// 传入的值为promise,直接返回
if(val instanceof this) {
return val
}
return new this((resolve, reject) => {
resolve(val)
})
}
// Promise.reject()
static reject(val) {
return new this((resolve, reject) => {
reject(val)
})
}
// Promise.all()
static all(promises) {
return new this((resolve, reject) => {
let len = promises.length
let count = 0
let result = new Array(len)
for(let i = 0; i < len; i++) {
// 传入非promise的参数,需转为promise
this.resolve(promises[i]).then((res) => {
count++
result[i] = res
if(count === len) {
resolve(result)
}
}, (err) => {
reject(err)
})
}
})
}
// Promise.race()
static race(promises) {
return new this((resolve, reject) => {
for(let i = 0; i <promises.length; i++) {
this.resolve(promises[i]).then(res => {
resolve(res)
}, err => {
reject(err)
})
}
})
}
constructor(executor) {
this.status = PENDING // 状态
this.resolveVal = null // resolve的值
this.rejectVal = null // reject的值
this.onFulfilledFnArr = [] // 收集then方法fulfilled的回调
this.onRejectedFnArr = [] // 收集then方法rejected的回调
const resolve = (val) => {
// 在resolve中传入promise对象,直接执行其then函数
if (val instanceof this.constructor) {
val.then(resolve, reject)
return
}
if(this.status === PENDING) {
this.status = FULFILLED
this.resolveVal = val
myNextTick(() => {
this.onFulfilledFnArr.forEach(item => {
item(this.resolveVal)
})
});
}
}
const reject = (err) => {
if(this.status === PENDING) {
this.status = REJECTED
this.rejectVal = err
myNextTick(() => {
this.onRejectedFnArr.forEach(item => {
item(this.rejectVal)
})
});
}
}
// 实例化promise时传递的函数
executor(resolve, reject)
}
// then函数传入的回调为微任务执行,所以使用myNextTick处理变为微任务
then(onFulfilledFn, onRejectedFn) {
// then方法返回一个promise
return new MyPromise((resolve, reject) => {
let callbackVal = null
if (this.status === FULFILLED) {
myNextTick(() => {
try {
callbackVal = onFulfilledFn && onFulfilledFn(this.resolveVal)
resolve(callbackVal)
} catch(error) {
reject(error)
}
});
} else if(this.status === REJECTED) {
myNextTick(() => {
try {
// then方法没传第二个参数,则一直reject,到底触发Promise.catch
if(!onRejectedFn) {
reject(this.rejectVal)
} else {
callbackVal = onRejectedFn(this.rejectVal)
resolve(callbackVal)
}
} catch(error) {
reject(error)
}
});
} else if (this.status === PENDING) {
// 当promise处于pending状态,则收集then方法传入的回调,
// 在状态改变时再执行这些回调
onFulfilledFn && this.onFulfilledFnArr.push((val) => {
try {
callbackVal = onFulfilledFn(val)
resolve(callbackVal)
} catch(error) {
reject(error)
}
})
this.onRejectedFnArr.push((val) => {
try {
// then方法没传第二个参数,则一直reject,到底触发Promise.catch
if(!onRejectedFn) {
reject(val)
} else {
callbackVal = onRejectedFn(val)
resolve(callbackVal)
}
} catch(error) {
reject(error)
}
})
}
})
}
// catch为then的语法糖
catch(onRejectedFn) {
return this.then(null, onRejectedFn)
}
}
let p = new MyPromise((resolve, reject) => {
// 1. 普通状态改变
// resolve(10); // reject(10)
// 2. 延时状态改变
setTimeout(() => {
resolve(10); // reject(new Error('错误'))
// console.log('验证then方法为异步')
}, 1000);
// 3. resolve传入新的promise
// resolve(new MyPromise((resolve2, reject2) => {
// setTimeout(() => {
// resolve2(10)
// }, 1000);
// }))
})
p.then(res => {
console.log('一次then', res)
// throw new Error('haha')
return 20
}).then(res => {
console.log('二次then', res)
return 30
}).catch(err => {
console.log('catch', err)
})
// MyPromise.race()
// let p1 = new MyPromise((resolve, reject) => {
// setTimeout(() => {
// resolve(1)
// }, 2000);
// })
// let p2 = new MyPromise((resolve, reject) => {
// setTimeout(() => {
// resolve(2)
// }, 1000);
// })
// let p3 = new MyPromise((resolve) => {
// setTimeout(() => {
// resolve(3)
// }, 3000);
// })
// let p = MyPromise.race([p1, p2, p3])
// p.then(res => {
// console.log(res)
// }, err => {
// console.log('出错:', err)
// })
</script>