实现Promise核心功能
基本功能初步实现
测试代码
const promise = new MyPromise((resolve, reject) => {
// resolve('success')
reject('err')
})
promise.then(value => {
console.log('resolve', value)
}, reason => {
console.log('reject', reason)
})
初步实现:能够通过MyPromise创建promise实例,通过resolve和reject函数实现改变promise状态和存储结果,给promise实例绑定then函数,then函数能够通过promise实例状态执行相应回调onFulfilled/onRejected
const PENDING = 'pending'
const FULFULLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
const resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFULLED
this.value = value
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
}
}
executor(resolve, reject)
}
then (onFulfilled, onRejected) {
if (this.status === FULFULLED) {
onFulfilled(this.value)
} else if (this.status === REJECTED) {
onRejected(this.reason)
}
}
}
异步处理
测试代码修改为
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('success') // 异步执行resolve
}, 2000);
})
promise.then(value => {
console.log('resolve', value)
}, reason => {
console.log('reject', reason)
})
会发现控制台没有输出,这是因为then会同步执行,而executor内部异步执行。在进行then内部的状态判断时,promise实例状态还是pending,无法打印测试代码中第8行或第10行
通过在then中存储成功或失败的回调函数(onFulfilled或onRejected),等到executor内部执行resolve或reject时再执行回调onFulfilled或onRejected
const PENDING = 'pending'
const FULFULLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
// 新增
// 存储成功与失败的回调
this.onFulfilledCallback = {}
this.onRejectedCallback = {}
const resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFULLED
this.value = value
// 新增
this.onFulfilledCallback && this.onFulfilledCallback(value)
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
// 新增
this.onRejectedCallback && this.onRejectedCallback(reason)
}
}
executor(resolve, reject)
}
then (onFulfilled, onRejected) {
if (this.status === FULFULLED) {
onFulfilled(this.value)
} else if (this.status === REJECTED) {
onRejected(this.reason)
}
// 新增
else if (this.status === PENDING) {
this.onFulfilledCallback = onFulfilled
this.onRejectedCallback = onRejected
}
}
}
异步处理多次调用then
测试代码
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 2000);
})
promise.then(value => {
console.log('resolve', value)
})
promise.then(value => {
console.log('resolve', value)
})
promise.then(value => {
console.log('resolve', value)
})
期望输出:2s后打印
实际输出
resolve success
因为多次调用then,后面的成功回调会覆盖前面的,需要将存储回调函数的变量设置为数组
const PENDING = 'pending'
const FULFULLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
// 修改
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
const resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFULLED
this.value = value
// 修改
while (this.onFulfilledCallbacks.length) { // 0 ==> false
this.onFulfilledCallbacks.shift()(value)
}
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
// 修改
while (this.onRejectedCallbacks.length) {
this.onRejectedCallbacks.shift()(reason)
}
}
}
executor(resolve, reject)
}
then (onFulfilled, onRejected) {
if (this.status === FULFULLED) {
onFulfilled(this.value)
} else if (this.status === REJECTED) {
onRejected(this.reason)
}
// 修改
else if (this.status === PENDING) {
this.onFulfilledCallbacks.push(onFulfilled)
this.onRejectedCallbacks.push(onRejected)
}
}
}
实现then的链式调用
先只考虑成功回调的情况
onFulfilled返回非promise
实现每个then函数返回一个promise,且成功回调返回非promise
then (onFulfilled, onRejected) {
if (this.status === RESOLVED) {
onFulfilled(this.value)
}
else if (this.status === REJECTED) {
onRejected(this.reason)
}
else if (this.status === PENDING) {
this.onResolvedCallbacks.push(onFulfilled)
this.onRejectedCallbacks.push(onRejected)
}
}
根据规范,每个then必返回一个promise,修改一下上面代码
then (onFulfilled, onRejected) {
const promise2 = new MyPromise((resolve, reject) => { // 新增
if (this.status === FULFULLED) {
onFulfilled(this.value)
}
// else if ...
// rejected 和 pending 暂时省略
})
return promise2 // 新增
}
测试代码
const p1 = new MyPromise((res, rej) => {
res('ok')
})
p1
.then(value => {
console.log(1)
console.log('resolve', value)
return 1
})
.then(value => {
console.log(2)
console.log('resolve', value)
})
输出结果
1
resolve ok
发现第二个then并没有执行,这是因为第一个then返回的promise实际上是
主要问题出在第一个.then中new Promise的executor并没有执行resolve或reject来修改promise的状态,所以return的promise2是pending状态,此时再去执行第二个.then,判断promise实例状态时会把onFulfilled函数推入onFulfilledCallbacks数组而不是去执行这个成功回调,也就不会打印
继续修改,定义一个x存储onFulfilled的返回值,加入resolve(x)改变promise2的状态
then (onFulfilled, onRejected) {
const promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFULLED) {
const x = onFulfilled(this.value)//新增
resolve(x) //新增
}
// else if ...
// rejected 和 pending暂时省略
})
return promise2
}
此时输出结果与原生Promise一致
onFulfilled返回promise
测试代码修改5~10,16行
const p1 = new MyPromise((res, rej) => {
res('ok')
})
// 新增
function other () {
return new MyPromise((resolve, reject) => {
resolve('other')
})
}
p1
.then(value => {
console.log(1)
console.log('resolve', value)
return other() // 返回promise
})
.then(value => {
console.log(2)
console.log('resolve', value)
})
输出结果与原生不一致
这是因为x存储了onFulfilled回调返回的promise(other生成的那个),第一个then的返回值promise2属性值如下
so需要加一层判断,当x为MyPromise类型时,进行二次处理
const x = onFulfilled(this.value)
if (x instanceof MyPromise) {
x.then(value => resolve(value), reason => reject(reason)) // 新增
} else {
resolve(x)
}
执行完第3行,调用的then中返回的x为
打印结果🥰🥳
把这部分业务逻辑抽离出来,在class外面定义一个新的函数resolvePromise()
class MyPromise {
//...constructor
then (onFulfilled, onRejected) {
const promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFULLED) {
const x = onFulfilled(this.value)
resolvePromise(x, resolve, reject) // 调用resolvePromise
}
// else if ...
// rejected 和 pending暂时省略
})
return promise2 // 新增
}
}
function resolvePromise (x, resolve, reject) {
if (x instanceof MyPromise) {
x.then(value => resolve(value), reason => reject(reason))
} else {
resolve(x)
}
}
识别Promise是否返回自己
如果 then 方法返回的是自己的 Promise 对象,则会发生循环调用,这个时候程序会报错
// test.js const promise = new Promise((resolve, reject) => { resolve(100) }) const p1 = promise.then(value => { console.log(value) return p1 })100 Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>
如果then的返回值和onFulfilled返回值相同,说明返回的是自己
修改resolvePromise,创建微任务(等待promise2完成初始化)
then (onFulfilled, onRejected) {
const promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFULLED) {
queueMicrotask(() => { // 微任务
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
})
}
// else if ...
// rejected 和 pending暂时省略
return promise2
}
function resolvePromise (promise2, x, resolve, reject) {
// 新增调用自己的判断
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (x instanceof MyPromise) {
x.then(value => resolve(value), reason => reject(reason))
} else {
resolve(x)
}
}
测试代码
const promise = new MyPromise((resolve, reject) => {
resolve('success')
})
// 这个时候将promise定义一个p1,然后返回的时候返回p1这个promise
const p1 = promise.then(value => {
console.log(1)
console.log('resolve', value)
return p1
})
// 运行的时候会走reject
p1.then(value => {
console.log(2)
console.log('resolve', value)
}, reason => {
console.log(3)
console.log(reason.message)
})
结果
错误捕获
执行器错误
class MyPromise {
constructor(executor) {
// 省略初始化和resolve、reject
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
// 省略then
}
测试代码
const p1 = new MyPromise((res, rej) => {
throw new Error('执行器错误')
})
p1.then((value) => {
console.log(1);
console.log(value);
}, (reason) => {
console.log(2)
console.log(reason.message);
})
then 执行的时错误捕获
then (onFulfilled, onRejected) {
const promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFULLED) {
queueMicrotask(() => {
// 新增
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
// else if
})
return promise2
}
}
测试代码
const promise = new MyPromise((resolve, reject) => {
resolve('success')
// throw new Error('执行器错误')
})
// 第一个then方法中的错误要在第二个then方法中捕获到
promise
.then(value => {
console.log(1)
console.log('resolve', value)
throw new Error('then error')
}, reason => {
console.log(2)
console.log(reason.message)
})
.then(value => {
console.log(3)
console.log(value);
}, reason => { // 打印这里
console.log(4)
console.log(reason.message)
})
rejected和pending状态
const p1 = new MyPromise((res, rej) => {
rej('p1状态为rejected')
})
function other () {
return new MyPromise((resolve, reject) => {
resolve('other')
})
}
p1
.then(value => {
console.log(1)
console.log('resolve', value)
}, reason => {
console.log(2)
console.log('reject', reason);
return other()
})
.then(value => {
console.log(3)
console.log('resolve', value)
}, reason => {
console.log(4)
console.log('reject', reason);
})
修改代码
then (onFulfilled, onRejected) {
const promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFULLED) {
queueMicrotask(() => {
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
else if (this.status === REJECTED) {
/* 新增 */
queueMicrotask(() => {
try {
const x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
else if (this.status === PENDING) {
/* 新增 */
this.onFulfilledCallbacks.push(() => {
queueMicrotask(() => {
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
})
/* 新增 */
this.onRejectedCallbacks.push(() => {
queueMicrotask(() => {
try {
const x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
})
}
})
return promise2
}
}
then中参数变为可选
判断then传入的参数,如果不是函数,就使用默认函数
then (onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => reason;
const promise2 = new MyPromise((resolve, reject) => {
//...
测试代码
// test.js
const promise = new MyPromise((resolve, reject) => {
resolve('succ')
// reject('err')
})
promise.then().then().then(value => console.log(value), reason => console.log(reason))
// 打印 succ / err
实现resolve与reject的静态调用
class MyPromise {
static resolve (parameter) {
if (parameter instanceof MyPromise) {
return parameter
}
return new MyPromise(resolve => {
resolve(parameter)
})
}
static reject (reason) {
return new MyPromise((resolve, reject) => {
reject(reason)
})
}
}
测试代码
MyPromise.resolve().then(() => {
console.log(0);
return MyPromise.resolve(4);
}).then((res) => {
console.log(res)
})
实现Promise.all()
Promise.myAll = (promises) => {
// 存放每个resolved promise结果
let result = []
// 计数器
let count = 0
// 当计数器和数组长度相等,就说明promise全部为resolved
const len = promises.length
return new Promise((resolve, reject) => {
if (len === 0) {
return resolve([])
}
promises.forEach((p, i) => {
// 注意数组项可能不是promise,需要转化
Promise.resolve(p).then((res) => {
count++
// 收集每个promise返回值
result[i] = res
if (count === len) {
resolve(result)
}
// 数组项只要有一个失败,就返回这个失败的promise
}).catch(reject)
});
})
}
// 测试一下
const p1 = Promise.resolve(1)
const p2 = new Promise((resolve) => {
setTimeout(() => resolve(2), 1000)
})
const p3 = new Promise((resolve) => {
setTimeout(() => resolve(3), 3000)
})
const p4 = Promise.reject('err4')
const p5 = Promise.reject('err5')
// 1. 所有的Promise都成功了
const p11 = Promise.myAll([p1, p2, p3])
.then(console.log) // [ 1, 2, 3 ]
.catch(console.log)
// 2. 有一个Promise失败了
const p12 = Promise.myAll([p1, p2, p4])
.then(console.log)
.catch(console.log) // err4
// 3. 有两个Promise失败了,可以看到最终输出的是err4,第一个失败的返回值
const p13 = Promise.myAll([p1, p4, p5])
.then(console.log)
.catch(console.log) // err4
// 与原生的Promise.all返回是一致的
const p14 = Promise.myAll([]).then(console.log).catch(console.log)