在 JavaScript
中,Promise
是一种用于处理异步操作的对象,它可以让异步代码更易于理解和管理。在本文中,我们将手写实现一个 Promise
对象实现其resolve
、reject
、then
和catch
方法。
在介绍 Promise
的实现方法之前,让我们先回顾一下 Promise
的基本概念。
Promise
有三种状态:
Pending
(进行中):初始状态,表示 Promise
实例正在进行中。Fulfilled
(已完成):表示异步操作已经完成,并且 Promise
实例已经获得了一个值。Rejected
(已失败):表示异步操作已经失败,并且 Promise
实例已经获得了一个失败原因。当 Promise
实例从 Pending
状态转变为 Fulfilled
或者 Rejected
状态时,我们称之为 Promise
已经 settled
(已敲定)。
我们将使用 ES6
的类来实现一个 Promise
。Promise
类需要具备以下功能:
executor
函数作为参数,该函数将在 Promise
实例创建时立即执行,并传递两个回调函数,即 resolve
和 reject
函数。executor
函数内部,我们需要处理异步操作,如果操作成功,则使用 resolve
函数返回结果;如果操作失败,则使用 reject
函数返回错误信息。Promise
实例需要提供 then
方法,该方法接受两个回调函数,即 onFulfilled
和 onRejected
,分别在 Promise
转变为 Fulfilled
或者 Rejected
状态时执行。executor
函数执行过程中发生错误,Promise
实例应该转变为 Rejected
状态,并且使用 reject
函数返回错误信息。Promise
实例可以链式调用 then
方法,每个 then
方法可以返回一个新的 Promise
实例,实现 Promise
链。Promise
实例需要提供 catch
方法,用于捕获 promise
对象的拒绝状态rejected
的回调函数,它同样支持链式调用。下面是我们的 Promise
类的基本实现:
javascriptclass Promise {
static Pending = "Pending";
static Fulfilled = "Fulfilled";
static Rejected = "Rejected";
constructor(executor) {
this.status = Promise.Pending;
this.value = null;
this.reason = null;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
reject(error);
}
}
resolve(value) {
if (this.status === Promise.Pending) {
this.status = Promise.Fulfilled;
this.value = value;
this.onFulfilledCallbacks.forEach((callback) => {
callback(this.value);
});
}
}
reject(reason) {
if (this.status === Promise.Pending) {
this.status = Promise.Rejected;
this.reason = reason;
this.onRejectedCallbacks.forEach((callback) => {
callback(this.reason);
});
}
}
then(onFulfilled, onRejected) {
return new Promise((resolve, reject) => {
if (this.status === Promise.Fulfilled) {
setTimeout(() => {
try {
const result = onFulfilled(this.value);
resolve(result);
} catch (error) {
reject(error);
}
});
}
if (this.status === Promise.Rejected) {
setTimeout(() => {
try {
const result = onRejected(this.reason);
resolve(result);
} catch (error) {
reject(error);
}
});
}
if (this.status === Promise.Pending) {
this.onFulfilledCallbacks.push((value) => {
setTimeout(() => {
try {
const result = onFulfilled(value);
resolve(result);
} catch (error) {
reject(error);
}
});
});
this.onRejectedCallbacks.push((reason) => {
setTimeout(() => {
try {
const result = onRejected(reason);
resolve(result);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
}
我们先创建了一个 Promise
类,其中包含了 Promise
的基本属性和方法。在构造函数中,我们定义了 status
、value
、reason
三个变量用于保存 Promise 的状态和值,以及 onFulfilledCallbacks
和 onRejectedCallbacks
两个数组用于保存 then
方法中传入的回调函数。
在随后的 try-catch
语句中,我们调用了 executor
函数,并将之后实现的 resolve
和 reject
函数传入,以便在异步操作完成后调。
需要注意的是,我们需要通过this.xxx.bind(this)
的方法来传入resolve
和reject
函数,否则在这两个函数内无法访问到当前类的任何东西,这是一个JavaScript
中的this
指向问题,你可以从resolve
和reject
函数在实际应用中的调用过程来思考这个问题。
然后,我们实现了 resolve
和 reject
两个函数,分别用于处理 Promise
的 Fulfilled
和 Rejected
状态。
接下来,我们实现了 then
函数。当 Promise
的状态为 Fulfilled
时,我们使用 setTimeout
函数将 onFulfilled
回调函数放入微任务队列中,以确保在本轮事件循环结束后执行。同样的,当 Promise
的状态为 Rejected
时,我们使用 setTimeout
函数将 onRejected
回调函数放入微任务队列中。
当 Promise
的状态为 Pending
时,我们将 onFulfilled
和 onRejected
回调函数保存到 onFulfilledCallbacks
和 onRejectedCallbacks
数组中,并在异步操作完成后执行。
然后,我们返回一个新的 Promise
实例,该实例包含了一个 executor
函数。在 executor
函数中,我们根据当前 Promise
的状态决定调用 onFulfilled
或 onRejected
回调函数,并将执行结果传递给 resolve
或 reject
函数。
最后,我们实现了catch
函数,Promise
中的catch
方法是用于捕获promise
对象的拒绝状态(rejected)
的回调函数,它相当于调用then
方法时传入一个undefined
作为第一个参数,而将回调函数作为第二个参数。
现在,我们可以使用手写的 Promise
类来处理异步操作了。下面是一个简单的例子:
javascriptconst promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Hello, world!');
}, 1000);
});
promise
.then((result) => {
console.log(result);
return 'Goodbye, world!';
})
.then((result) => {
console.log(result);
})
.catch((error) => {
console.error(error);
});
在这个例子中,我们创建了一个 Promise
实例,并在 1 秒钟后将状态设置为 Fulfilled
,并返回一个字符串。
然后,我们链式调用了两个 then
方法,第一个方法打印了字符串并返回了一个新的字符串,第二个方法又打印了新的字符串。
最后,我们调用了 catch
方法,以处理任何可能发生的错误。
Promise
是一种非常强大的异步编程技术,可以使我们更加轻松地管理异步代码。通过手写实现 Promise
,我们可以更好地理解 Promise
的工作原理,并更加深入地了解 JavaScript
的异步编程模型。
本文作者:CreatorRay
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!