破解Then、Catch的链式调用:用最简单的Promise实现
2023-12-23 01:35:29
在步入Promise的实现之旅前,我并未深入研究过A+规范。我通过在控制台中反复试验原生Promise,摸索出了它的特性。我也阅读了一些面试文章,发现它们实现的Promise功能并不全面,而且有些复杂。但庆幸的是,我读到了晨曦时梦见兮大神的Promise极简实现,它巧妙地实现了then的链式调用。
在此基础上,我决定动手打造一个更精简、功能更完备的Promise实现。在我看来,Promise是一个非常优雅的构造,它消除了回调函数的嵌套,让异步编程变得更加清晰简洁。
then、catch的链式调用
then和catch是Promise中不可或缺的两个方法。then用于处理Promise的结果,而catch用于捕获和处理异常。它们的链式调用可以让我们优雅地处理多个异步操作,形成一个流水线式的流程。
举个例子,我们可以使用then链式调用来实现一个简单的异步文件读取操作:
const readFilePromise = new Promise((resolve, reject) => {
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
readFilePromise
.then(data => {
console.log('File contents:', data);
return data.toUpperCase();
})
.then(uppercaseData => {
console.log('Uppercase file contents:', uppercaseData);
})
.catch(err => {
console.error('Error reading file:', err);
});
在这个例子中,第一个then处理文件读取的结果,并将其转换为大写。第二个then进一步处理大写后的结果,并打印它。如果在任何阶段发生错误,catch块将捕获并处理该错误。
实现then和catch
实现then和catch的关键在于巧妙地利用JavaScript的原型和闭包。
首先,我们定义一个Promise构造函数,它接受一个执行器函数作为参数。执行器函数又接受resolve和reject两个回调函数,用于通知Promise结果或错误。
function Promise(executor) {
this.state = 'pending'; // 初始状态为pending
this.value = undefined; // 结果值
this.reason = undefined; // 错误原因
this.onFulfilledCallbacks = []; // 存储then回调
this.onRejectedCallbacks = []; // 存储catch回调
// 执行器函数执行resolve或reject
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
接下来,我们定义then方法。then接受两个回调函数作为参数,分别处理结果和错误。如果Promise当前处于pending状态,则将回调函数存储在相应的数组中,等待Promise结果或错误。如果Promise已经完成(即处于fulfilled或rejected状态),则直接执行对应的回调函数。
Promise.prototype.then = function(onFulfilled, onRejected) {
return new Promise((resolve, reject) => {
// 将回调函数存储在相应的数组中
this.onFulfilledCallbacks.push(() => {
// 调用onFulfilled回调,并用结果调用resolve
try {
const result = onFulfilled(this.value);
resolve(result);
} catch (err) {
reject(err);
}
});
this.onRejectedCallbacks.push(() => {
// 调用onRejected回调,并用错误原因调用reject
try {
const reason = onRejected(this.reason);
resolve(reason);
} catch (err) {
reject(err);
}
});
// 如果Promise已经完成,则直接执行回调函数
if (this.state === 'fulfilled') {
this.onFulfilledCallbacks[0]();
} else if (this.state === 'rejected') {
this.onRejectedCallbacks[0]();
}
});
};
catch方法的实现与then类似,但它只接受一个处理错误的回调函数。如果Promise当前处于pending状态,则将回调函数存储在onRejectedCallbacks数组中。如果Promise已经处于rejected状态,则直接执行回调函数。
Promise.prototype.catch = function(onRejected) {
return this.then(null, onRejected);
};
结语
至此,我们已经实现了一个简单但功能完备的Promise。它支持then和catch的链式调用,可以优雅地处理异步操作。虽然它不如原生Promise强大,但对于许多常见的异步编程场景来说,它已经足够了。
希望这个实现能帮助你加深对Promise的理解,并激发你创建自己的异步编程解决方案。