思路
- constructor:通过 state 的状态执行 resolve 和reject
- 实现then方法:通过 state 判断执行 onFulfilled 还是 onRejected。
- 解决异步问题:在构造器中,如果 resolve 是通过异步返回的话,在执行 then 语句时,state 仍为 pending,所以可以通过将 onFulfilled 和 onRejected 先放到一个数组中,延迟到 resolve 时执行。
- 解决链式调用:在 then 中的 onFulfilled 中可以有两种情况:return 普通的值;return 一个新的 promise
所以就需要先判断一下 onFulfilled return 的值类型,如果是 promise 时,就将此 promise resolve 的值给 promise2,否则直接 resolve。这一过程中可能存在递归。
- 一些细节:
- onFulfilled 和 onRejected 可以不是 function,需要做兼容
- onRejected 时,需要 throw,否则会传到下一个 then 中
- onFulfilled 和 onRejected 可能为 null
- onFulfilled 可能 return null
- try catch 块的捕捉
code
class Promise {
constructor(executor) {
this.state = 'pending'
this.value = undefined
this.reason = undefined
// 解决异步问题,回调延迟执行
this.resolveCbs = []
this.rejectCbs = []
let resolve = v => {
if(this.state === 'pending') {
this.state = 'fulfilled'
this.value = v
// console.log('onResolve')
for(let cb of this.resolveCbs) {
cb()
}
}
}
let reject = e => {
if(this.state === 'pending') {
this.state = 'rejected'
this.reason = e
// console.log('onReject')
for(let cb of this.rejectCbs) {
cb()
}
}
}
try {
executor(resolve, reject);
}
catch(e) {
reject(e)
}
}
/**
* onFulfilled 有两种情况,要分别处理
* return v // 普通值,直接 resolve
* return promise // Promise,递归取得
*
* @param {*} fulfilled
* @param {*} rejected
*/
then(fulfilled, rejected) {
fulfilled = typeof fulfilled === 'function'? fulfilled: fulfilled => fulfilled
rejected = typeof rejected === 'function'? rejected: rejected => { throw rejected }
function resolvePromise(promise2, x, resolve, reject) {
if(x && x === promise2) {
return reject(new Error('循环调用,堆栈溢出'))
}
let called = false
if(x && (typeof x === 'object' || typeof x === 'function')) {
let then = x.then
try{
if(typeof then === 'function') {
// x 是 promise
then.call(x, fulfilled2 => {
if(called) return
called = true
resolvePromise(promise2, fulfilled2, resolve, reject)
}, rejected2 => {
if(called) return
called = true
reject(rejected2)
})
}
else {
return resolve(x)
}
}
catch(e) {
return reject(e)
}
}
else {
// 基本类型,直接 resolve
return resolve(x)
}
}
var promise2 = new Promise((resolve, reject) => {
// 同步
if(this.state === 'fulfilled') {
try{
let x = fulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
}
catch(e) {
reject(e)
}
}
else if(this.state === 'rejected') {
try{
let x = rejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
}
catch(e) {
reject(e)
}
}
// 异步,先把函数保存起来,等 resolve, reject 时再执行
else if(this.state === 'pending') {
// console.log('onThen: pending')
this.resolveCbs.push(() => {
try{
let x
if(fulfilled)
x = fulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
}
catch(e) {
reject(e)
}
})
this.rejectCbs.push(() => {
try{
let x
if(rejected)
x = rejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
}
catch(e) {
reject(e)
}
})
}
})
// return prosmise 解决链式调用
return promise2
}
catch(fn) {
return this.then(null, fn)
}
static resolve(v) {
return new Promise((resolve, reject) => {
resolve(v)
})
}
static reject(v) {
return new Promise((resolve, reject) => {
reject(v)
})
}
static race(promises) {
return new Promise((resolve, reject) => {
for(let promise of promises) {
promise
.then(resolve, reject)
}
});
}
static all(promises) {
return new Promise((resolve, reject) => {
let rsts = []
for(let promise of promises) {
promise
.then(v => {
rsts.push(v)
if(rsts.length === promises.length) {
return resolve(rsts)
}
}, reject)
}
});
}
static map(arr, fn, options) {
return new Promise((resolve, reject) => {
let promises = []
for(let v of arr) {
promises.push(fn(v))
}
Promise.all(promises)
.then(resolve, reject)
});
}
}
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 0);
console.log('async')
// resolve(1)
})
.then(v => {
console.log('onThen 1', v)
// return 普通值
// return 2
return Promise.reject(2)
// return promise 而且可能是promise嵌套的情况,此时要拿到最内层 promsie resolve 的值
// return new Promise((resolve, reject) => {
// return new Promise((resolve2, reject2) => {
// setTimeout(() => {
// resolve2(2)
// }, 0);
// })
// .then(v => {
// resolve(v)
// })
// })
})
.then(v => {
console.log('onThen 2', v)
})
.catch(e => {
console.log('catch')
})
// Promise.all([
// new Promise((resolve, reject) => {
// setTimeout(() => {
// resolve(1)
// }, 1000)
// }),
// new Promise((resolve, reject) => {
// setTimeout(() => {
// resolve(2)
// }, 200)
// })
// ])
// .then(console.info)
// .catch(console.error)
// Promise.map([1,2], v => {
// return Promise.resolve(v)
// })
// .then(console.info)
// .catch(console.error)
缺点
- then函数的独立作用域:无法访问每个回调函数的作用域(或者其中未返回的的变量)
- 不能取消:在网络延迟的情况下,有时候触发请求时需要取消上一次请求的监听
- 不能传递多值
- 非惰性求值,定义的时候就运行了,不能多处重用(订阅)。与RxJS相比,后者将事件的生产和消费分离,实现了惰性求值
参考