本文深入解析 JavaScript 中 Promise 的核心实现原理。通过 ES6 Class 语法,逐步构建包含 pending、fulfilled、rejected 三种状态的状态机。详细阐述 resolve 与 reject 的逻辑,实现 then 方法的链式调用、异步任务队列管理以及 catch 错误处理机制,完整还原 Promise 的核心 API 行为。
准备工作
- 首先,
promise拥有三种状态:pending、fulfilled和rejected; - 在实例化操作中,
promise包含两个用于改变状态的方法,分别为resolve和reject; promise提供了许多方法,详情请参考mdn。本篇文章将先实现promise的核心api:then和catch;
我们使用 es6 提供的 class 来实现
class MyPromise {
// 准备三个状态
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(executor) {
this.status = MyPromise.PENDING; // 表示promise的状态
this.value = null; // 表示promise的值
try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error)
}
}
resolve() {
}
reject() {
}
}
在这里,executor 是传递进来的函数,它可以接收 resolve 和 reject。这里将内部的两个方法传入,如果在调用过程中发生报错,会调用 reject 方法
完善 resolve/reject
它们的工作流程分为以下几步
- 将状态改为
pending,并分别设置为fulfilled或rejected - 可以接受一个值,作为当前
promise的value
resolve(value) {
if (this.status === MyPromise.PENDING) {
this.status = MyPromise.FULFILLED;
this.value = value
}
}
reject(value) {
if (this.status === MyPromise.PENDING) {
this.status = MyPromise.REJECTED;
this.value = value
}
}
then
then 函数可以接受两个参数,分别为成功的回调函数和失败的回调函数,并且这两个回调函数的默认值是一个函数
- 当状态为
fulfilled时执行第一个回调,状态为rejected时执行第二个回调 - 在回调函数中传入当前的
value then的执行是异步的
then(onFulfilled, onRejected) {
if (typeof onFulfilled !== 'function') {
onFulfilled = value => value
}
if (typeof onFulfilled !== 'function') {
onRejected = value => value
}
if (this.status === MyPromise.FULFILLED) {
setTimeout(() => {
onFulfilled(this.value)
})
}
if (this.status === MyPromise.REJECTED) {
setTimeout(() => {
onRejected(this.value)
})
}
}
验证一下:
console.log(1)
new MyPromise((resolve, reject) => {
console.log(2)
resolve('成功')
}).then(res => console.log(res))
console.log(3)
// 打印 1 2 3 成功
当 promise 里面包含异步代码的时候,此时运行到 .then 方法,状态为 pending,接下来增加对异步任务的处理
异步处理
当状态为 pending 的时候,表示执行的是异步任务。此时我们可以增加一个 callback,把异步执行的内容添加到这个 callback 中。当异步代码执行完毕后,会执行异步函数的 callback 任务
constructor(executor) {
// ...
this.callbacks = []; // 用来存储回调函数的容器
// ...
}
resolve(value) {
// ...
this.callbacks.forEach(({ onFulfilled }) => onFulfilled(value))
// 当执行到这里的时候 如果有onFulfilled 就说明已经执行完then方法给容器添加内容了。把resolve的值传递给onFulfilled
}
reject(value) {
// ...
this.callbacks.forEach(({ onRejected }) => onRejected(value))
// 当执行到这里的时候 如果有onRejected 就说明已经执行完then方法给容器添加内容了。把reject的值传递给onFulfilled
}
then(onFulfilled, onRejected) {
// ...
if (this.status === MyPromise.PENDING) {
this.callbacks.push({
onFulfilled: value => {
setTimeout(() => {
onFulfilled(value)
})
},
onRejected: value => {
setTimeout(() => {
onRejected(value)
})
}
})
}
}
验证一下:
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
})
}).then(res => console.log(res))
// 打印 成功
then 函数支持链式调用,接下来我们完善这一点
链式调用
链式调用的核心是返回一个新的 promise。当成功调用时,调用新的 promise 的 resolve;失败时调用 reject。并且链式调用会将前一个的返回值作为下一个 resolve 的状态
then(onFulfilled, onRejected) {
if (typeof onFulfilled !== 'function') {
onFulfilled = value => value
}
if (typeof onFulfilled !== 'function') {
onRejected = value => value
}
return new MyPromise((resolve, reject) => {
if (this.status === MyPromise.FULFILLED) {
setTimeout(() => {
const result = onFulfilled(this.value)
resolve(result)
})
}
if (this.status === MyPromise.REJECTED) {
setTimeout(() => {
const result = onRejected(this.value)
resolve(result)
})
}
if (this.status === MyPromise.PENDING) {
this.callbacks.push({
onFulfilled: value => {
setTimeout(() => {
const result = onFulfilled(value)
resolve(result)
})
},
onRejected: value => {
setTimeout(() => {
const result = onRejected(value)
resolve(result)
})
}
})
}
})
}验证一下:
new MyPromise((resolve, reject) => {
setTimeout(() => {
reject('失败')
})
}).then(res => res, err => err).then(res => console.log(res))
// 打印 失败
如果 .then 的回调函数返回的是 promise 的情况,也需要做相应处理
边界处理
实现前:
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
})
}).then(
res => new MyPromise((resolve, reject) => {
resolve(res)
}),
err => err
).then(res => console.log(res))
// 打印 { "status": "fulfilled", "value": "成功", "callbacks": [] }
当判断返回值为 MyPromise 的时候,需要手动调用 .then 的方法以获取其值,并且将当前 promise 的改变状态的函数透出给 then 方法
then(onFulfilled, onRejected) {
if (typeof onFulfilled !== 'function') {
onFulfilled = value => value
}
if (typeof onFulfilled !== 'function') {
onRejected = value => value
}
return new MyPromise((resolve, reject) => {
if (this.status === MyPromise.FULFILLED) {
setTimeout(() => {
const result = onFulfilled(this.value)
if (result instanceof MyPromise) {
result.then(resolve, reject)
} else {
resolve(result)
}
})
}
if (this.status === MyPromise.REJECTED) {
setTimeout(() => {
const result = onRejected(this.value)
if (result instanceof MyPromise) {
result.then(resolve, reject)
} else {
resolve(result)
}
})
}
if (this.status === MyPromise.PENDING) {
this.callbacks.push({
onFulfilled: value => {
setTimeout(() => {
const result = onFulfilled(value)
if (result instanceof MyPromise) {
result.then(resolve, reject)
} else {
resolve(result)
}
})
},
onRejected: value => {
setTimeout(() => {
const result = onRejected(value)
if (result instanceof MyPromise) {
result.then(resolve, reject)
} else {
resolve(result)
}
})
}
})
}
})
}
验证:
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
})
}).then(
res => new MyPromise((resolve, reject) => {
resolve(res)
}),
err => err
).then(res => console.log(res))
// 打印 成功
到这里,.then 方法就实现得差不多了。接下来实现 catch 方法
catch
catch 方法可以处理拒绝的状态和错误的状态:
catch(onFulfilled) {
if (typeof onFulfilled !== 'function') {
onFulfilled = value => value
}
return new MyPromise((resolve, reject) => {
if (this.status === MyPromise.REJECTED) {
setTimeout(() => {
const result = onFulfilled(this.value)
if (result instanceof MyPromise) {
result.then(resolve, reject)
} else {
resolve(result)
}
})
}
})
}
验证:
new MyPromise((resolve, reject) => {
reject('失败')
}).catch(res=> console.log(res))
// 打印 失败
道理其实和 then 是相同的。到这里主功能基本上就差不多了,但存在很多重复的地方,需要优化一下
优化后完整代码
class MyPromise {
// 准备三个状态
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(executor) {
this.status = MyPromise.PENDING; // 表示promise的状态
this.value = null; // 表示promise的值
this.callbacks = [];
try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
console.log(error)
this.reject(error)
}
}
resolve(value) {
if (this.status === MyPromise.PENDING) {
this.status = MyPromise.FULFILLED;
this.value = value
}
this.callbacks.forEach(({ onFulfilled }) => onFulfilled(value))
}
reject(value) {
if (this.status === MyPromise.PENDING) {
this.status = MyPromise.REJECTED;
this.value = value
}
this.callbacks.forEach(({ onRejected }) => onRejected(value))
}
parse({ callback, resolve, reject, value = this.value }) {
setTimeout(() => {
const result = callback(value)
if (result instanceof MyPromise) {
result.then(resolve, reject)
} else {
resolve(result)
}
})
}
then(onFulfilled, onRejected) {
if (typeof onFulfilled !== 'function') {
onFulfilled = value => value
}
if (typeof onFulfilled !== 'function') {
onRejected = value => value
}
return new MyPromise((resolve, reject) => {
if (this.status === MyPromise.FULFILLED) {
this.parse({ callback: onFulfilled, resolve, reject })
}
if (this.status === MyPromise.REJECTED) {
this.parse({ callback: onRejected, resolve, reject })
}
if (this.status === MyPromise.PENDING) {
this.callbacks.push({
onFulfilled: value => {
this.parse({ callback: onFulfilled, resolve, reject, value })
},
onRejected: value => {
this.parse({ callback: onRejected, resolve, reject, value })
}
})
}
})
}
catch(onFulfilled) {
if (typeof onFulfilled !== 'function') {
onFulfilled = value => value
}
return new MyPromise((resolve, reject) => {
if (this.status === MyPromise.REJECTED) {
this.parse({ callback: onFulfilled, resolve, reject })
}
})
}
}到此这篇关于 JavaScript 手写 Promise 核心原理的文章就介绍到这了,更多相关 JavaScript Promise 内容请搜索本站以前的文章或继续浏览下面的相关文章,希望大家以后多多支持本站!