一、创建一个类,进行初始化操作
- 这里需要注意的是,promise 方法包含三种状态:pending、fulfilled、rejected
class MyPromise {
constructor() {
this.initValue()
}
initValue() {
this.promiseState = "pending"
this.promiseResult = null
}
}
二、添加 resolve 和 reject 方法,并进行 bind 操作
class MyPromise {
constructor() {
this.initValue()
this.initBind()
}
initValue() {
this.promiseState = "pending"
this.promiseResult = null
}
initBind() {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
resolve(value) {
}
reject(reason) {
}
}
三、在 constructor 中,传入一个执行参数,执行 promise 的 resolve 和 reject 方法;使用 try catch 捕获 promise 中的 throw,并且执行 reject 方法
class MyPromise {
constructor(executor) {
this.initValue()
this.initBind()
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
initValue() {
this.promiseState = "pending"
this.promiseResult = null
}
initBind() {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
resolve(value) {
}
reject(reason) {
}
}
四、完善 resolve 和 reject 方法
- 这里需要注意的是,promise 的三种状态,不可逆向改变
class MyPromise {
constructor(executor) {
this.initValue()
this.initBind()
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
initValue() {
this.promiseState = "pending"
this.promiseResult = null
}
initBind() {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
resolve(value) {
if(this.promiseState !== "pending") return
this.promiseState = "fulfilled"
this.promiseResult = value
}
reject(reason) {
if(this.promiseState !== "pending") return
this.promiseState = "rejected"
this.promiseResult = reason
}
}
五、验证一下
- 1、实例化 MyPromise 后,传入成功或者失败的回调,状态值是否发生改变
- 2、在 MyPromise 中 throw,是否会改变状态,并且捕获到异常
六、实现 then 方法
- then 方法中传入两个回调函数,成功回调和失败回调
- 当状态发生改变后,如果是 fulfilled 状态,则执行成功回调,并将结果值传入成功回调
- 当状态发生改变后,如果是 rejected 状态,则执行失败回调,并将结果值传入失败回调
class MyPromise {
constructor(executor) {
this.initValue()
this.initBind()
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
initValue() {
this.promiseState = "pending"
this.promiseResult = null
}
initBind() {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
resolve(value) {
if(this.promiseState !== "pending") return
this.promiseState = "fulfilled"
this.promiseResult = value
}
reject(reason) {
if(this.promiseState !== "pending") return
this.promiseState = "rejected"
this.promiseResult = reason
}
then(onFulfilled, onRejected) {
if(this.promiseState === "fulfilled") {
onFulfilled(this.promiseResult)
}
if(this.promiseState === "rejected") {
onRejected(this.promiseResult)
}
}
}
七、验证 then 方法
八、先来看一下一个 promise 原生的例子
- 如上图所示,异步执行 resolve 方法时,p 在调用的那一刻是 pending 状态,5秒之后才会执行 resolve 方法。
- 再看一下,我们的 MyPromise 是否支持这样的功能,如下图
- 如上所示,我们的 MyPromise 目前不支持这样的功能。好的,没关系,我们来实现一下!
九、实现 resolve 和 reject 的异步触发
- 思路:
- 初始化的时候,创建成功的回调数组和失败的回调数组
- 在 then 方法中,判断状态是否为 pending,如果是 pending,则将成功回调和失败回调分别添加到成功回调数组和失败回调数组
- 在 resolve 方法和 reject 方法中,遍历回调函数数组,如果有则执行,并且执行后清除这一项
class MyPromise {
constructor(executor) {
this.initValue()
this.initBind()
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
initValue() {
this.promiseState = "pending"
this.promiseResult = null
// 初始化的时候,创建成功的回调数组和失败的回调数组
this.onFulfilledCallBacks = []
this.onRejectedCallBacks = []
}
initBind() {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
resolve(value) {
if (this.promiseState !== "pending") return
this.promiseState = "fulfilled"
this.promiseResult = value
// 遍历回调函数数组,如果有则执行,并且执行后清除这一项
while (this.onFulfilledCallBacks.length) this.onFulfilledCallBacks.shift()(this.promiseResult)
}
reject(reason) {
if (this.promiseState !== "pending") return
this.promiseState = "rejected"
this.promiseResult = reason
// 遍历回调函数数组,如果有则执行,并且执行后清除这一项
while (this.onRejectedCallBacks.length) this.onRejectedCallBacks.shift()(this.promiseResult)
}
then(onFulfilled, onRejected) {
// 在 then 方法中,判断状态是否为 pending,如果是 pending,则将成功回调和失败回调分别添加到成功回调数组和失败回调数组
if (this.promiseState === "pending") {
this.onFulfilledCallBacks.push(onFulfilled)
this.onRejectedCallBacks.push(onRejected)
}
if (this.promiseState === "fulfilled") {
onFulfilled(this.promiseResult)
}
if (this.promiseState === "rejected") {
onRejected(this.promiseResult)
}
}
}
十、验证 resolve 和 reject 的异步触发
十一、实现 then 的链式调用
class MyPromise {
constructor(executor) {
this.initValue()
this.initBind()
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
initValue() {
this.promiseState = "pending"
this.promiseResult = null
// 初始化的时候,创建成功的回调数组和失败的回调数组
this.onFulfilledCallBacks = []
this.onRejectedCallBacks = []
}
initBind() {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
resolve(value) {
if (this.promiseState !== "pending") return
this.promiseState = "fulfilled"
this.promiseResult = value
// 遍历回调函数数组,如果有则执行,并且执行后清除这一项
while (this.onFulfilledCallBacks.length) this.onFulfilledCallBacks.shift()(this.promiseResult)
}
reject(reason) {
if (this.promiseState !== "pending") return
this.promiseState = "rejected"
this.promiseResult = reason
// 遍历回调函数数组,如果有则执行,并且执行后清除这一项
while (this.onRejectedCallBacks.length) this.onRejectedCallBacks.shift()(this.promiseResult)
}
then(onFulfilled, onRejected) {
var thenPromise = new MyPromise((resolve, reject) => {
var handlePromiseCallback = cb => {
queueMicrotask(() => {
try {
var x = cb(this.promiseResult)
if (x === thenPromise) {
throw "Can Not Return Self"
return
}
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
} catch (error) {
reject(error)
}
})
}
// 在 then 方法中,判断状态是否为 pending,如果是 pending,则将成功回调和失败回调分别添加到成功回调数组和失败回调数组
if (this.promiseState === "pending") {
this.onFulfilledCallBacks.push(handlePromiseCallback.bind(this, onFulfilled))
this.onRejectedCallBacks.push(handlePromiseCallback.bind(this, onRejected))
}
if (this.promiseState === "fulfilled") {
// onFulfilled(this.promiseResult)
handlePromiseCallback(onFulfilled)
}
if (this.promiseState === "rejected") {
// onRejected(this.promiseResult)
handlePromiseCallback(onRejected)
}
})
return thenPromise
}
}
-
这一步,只改动了 then 方法。说一下,我们都做了什么:
- then 方法返回一个 promise 对象,所以实现了链式调用
- promise.then 是一个微任务,所以我们使用了 queueMicrotask API
- 对回调函数进行递归调用,返回值不能等于自身。如果返回值是 promise 对象,则继续执行 then 方法;如果不是,则执行成功回调
-
验证一下
十二、实现 then 方法的透传
- 先来看一下什么是 then 方法的透传?
- 所谓透传,就是在 then 方法中传入一个不是函数的值,在下一个 then 方法中依然可以获取到 resolve 或 reject 所传输的值
- 在我们的 MyPromise 中实现一下
class MyPromise {
constructor(executor) {
this.initValue()
this.initBind()
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
initValue() {
this.promiseState = "pending"
this.promiseResult = null
// 初始化的时候,创建成功的回调数组和失败的回调数组
this.onFulfilledCallBacks = []
this.onRejectedCallBacks = []
}
initBind() {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
resolve(value) {
if (this.promiseState !== "pending") return
this.promiseState = "fulfilled"
this.promiseResult = value
// 遍历回调函数数组,如果有则执行,并且执行后清除这一项
while (this.onFulfilledCallBacks.length) this.onFulfilledCallBacks.shift()(this.promiseResult)
}
reject(reason) {
if (this.promiseState !== "pending") return
this.promiseState = "rejected"
this.promiseResult = reason
// 遍历回调函数数组,如果有则执行,并且执行后清除这一项
while (this.onRejectedCallBacks.length) this.onRejectedCallBacks.shift()(this.promiseResult)
}
then(onFulfilled, onRejected) {
// 添加透传逻辑
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value
onRejected = typeof onRejected === "function" ? onRejected : reason => reason
var thenPromise = new MyPromise((resolve, reject) => {
var handlePromiseCallback = cb => {
queueMicrotask(() => {
try {
var x = cb(this.promiseResult)
if (x === thenPromise) {
throw "Can Not Return Self"
return
}
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
} catch (error) {
reject(error)
}
})
}
// 在 then 方法中,判断状态是否为 pending,如果是 pending,则将成功回调和失败回调分别添加到成功回调数组和失败回调数组
if (this.promiseState === "pending") {
this.onFulfilledCallBacks.push(handlePromiseCallback.bind(this, onFulfilled))
this.onRejectedCallBacks.push(handlePromiseCallback.bind(this, onRejected))
}
if (this.promiseState === "fulfilled") {
// onFulfilled(this.promiseResult)
handlePromiseCallback(onFulfilled)
}
if (this.promiseState === "rejected") {
// onRejected(this.promiseResult)
handlePromiseCallback(onRejected)
}
})
return thenPromise
}
}
- 验证一下
十三、实现 catch、finally 方法
class MyPromise {
constructor(executor) {
this.initValue()
this.initBind()
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
initValue() {
this.promiseState = "pending"
this.promiseResult = null
// 初始化的时候,创建成功的回调数组和失败的回调数组
this.onFulfilledCallBacks = []
this.onRejectedCallBacks = []
}
initBind() {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
resolve(value) {
if (this.promiseState !== "pending") return
this.promiseState = "fulfilled"
this.promiseResult = value
// 遍历回调函数数组,如果有则执行,并且执行后清除这一项
while (this.onFulfilledCallBacks.length) this.onFulfilledCallBacks.shift()(this.promiseResult)
}
reject(reason) {
if (this.promiseState !== "pending") return
this.promiseState = "rejected"
this.promiseResult = reason
// 遍历回调函数数组,如果有则执行,并且执行后清除这一项
while (this.onRejectedCallBacks.length) this.onRejectedCallBacks.shift()(this.promiseResult)
}
then(onFulfilled, onRejected) {
// 添加透传逻辑
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value
onRejected = typeof onRejected === "function" ? onRejected : reason => reason
var thenPromise = new MyPromise((resolve, reject) => {
var handlePromiseCallback = cb => {
queueMicrotask(() => {
try {
var x = cb(this.promiseResult)
if (x === thenPromise) {
throw "Can Not Return Self"
return
}
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
} catch (error) {
reject(error)
}
})
}
// 在 then 方法中,判断状态是否为 pending,如果是 pending,则将成功回调和失败回调分别添加到成功回调数组和失败回调数组
if (this.promiseState === "pending") {
this.onFulfilledCallBacks.push(handlePromiseCallback.bind(this, onFulfilled))
this.onRejectedCallBacks.push(handlePromiseCallback.bind(this, onRejected))
}
if (this.promiseState === "fulfilled") {
// onFulfilled(this.promiseResult)
handlePromiseCallback(onFulfilled)
}
if (this.promiseState === "rejected") {
// onRejected(this.promiseResult)
handlePromiseCallback(onRejected)
}
})
return thenPromise
}
catch(onRejected) {
return this.then(null, onRejected)
}
finally(cb) {
return this.then(
value => MyPromise.resolve(cb()).then(() => value),
reason => MyPromise.resolve(cb()).then(() => reason)
)
}
}
十四、实现静态方法 resolve、reject
static resolve(value) {
if (value instanceof MyPromise) return value
return new MyPromise((resolve, reject) => {
resolve(value)
})
}
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason)
})
}
十五、实现静态方法 all、race、allsettled、any
static all(promises) {
promises = Array.isArray(promises) ? promises : []
var index = 0
var result = []
return new MyPromise((resolve, reject) => {
if (promises.length === 0) {
resolve(result)
return
}
for (var i = 0; i < promises.length; i++) {
MyPromise.resolve(promises[i]).then(value => {
result[i] = value
if (++index === promises.length) {
resolve(result)
}
}).catch(reason => {
reject(reason)
})
}
})
}
static race(promises) {
promises = Array.isArray(promises) ? promises : []
return new MyPromise((resolve, reject) => {
for (let promise of promises) {
MyPromise.resolve(promise).then(value => {
resolve(value)
}).catch(reason => {
reject(reason)
})
}
})
}
static allsettled(promises) {
promises = Array.isArray(promises) ? promises : []
var index = 0
var result = []
return new MyPromise((resolve, reject) => {
if (promises.length === 0) {
resolve(result)
return
}
function handleResult(i, value, state) {
result[i] = {
value,
state
}
if (++index === promises.length) {
resolve(result)
}
}
for (var i = 0; i < promises.length; i++) {
MyPromise.resolve(promises[i]).then(value => {
handleResult(i, value, "fulfilled")
}).catch(reason => {
handleResult(i, reason, "rejected")
})
}
})
}
static any(promises) {
promises = Array.isArray(promises) ? promises : []
var index = 0
return new MyPromise((resolve, reject) => {
for (let promise of promises) {
MyPromise.resolve(promise).then(value => {
resolve(value)
}).catch(reason => {
if (++index === promises.length) {
reject("All Promises are Rejected")
}
})
}
})
}