这一小节是第四章的重点之一,朴灵作者在2013年时敏锐地捕捉到Promise即将成为异步编程的未来趋势(当时原生Promise还没普及,主要靠第三方库如Bluebird、Q、when.js)。他详细讲解了Promise的核心概念、Deferred模式,以及它如何优雅地解决回调地狱。
为什么需要Promise?
- 事件发布/订阅适合“一对多”解耦,但串行异步操作仍容易嵌套(回调地狱)。
- Promise的目标:把嵌套变成链式,让异步代码更线性、可读。
Promise的核心概念(A+规范)
Promise代表一个异步操作的最终结果,有三种状态:
- Pending:进行中
- Fulfilled(Resolved):成功
- Rejected:失败
状态不可逆,一旦确定就永久不变。
核心方法:
- then(onFulfilled, onRejected):链式调用,返回新Promise
- catch(onRejected):捕获错误
- finally(后来添加)
Deferred模式
当时很多库用Deferred对象来创建Promise(现在原生用new Promise):
- Deferred有resolve/reject方法控制状态。
- Promise是只读的“承诺”。
示例(书里风格,用当时流行库模拟):
// 模拟一个异步读取文件返回Promise的函数
function readFile(filename) {
const deferred = Q.defer(); // Q库的Deferred
fs.readFile(filename, 'utf8', (err, data) => {
if (err) deferred.reject(err); // 失败
else deferred.resolve(data); // 成功
});
return deferred.promise; // 返回只读Promise
}
// 使用:链式调用
readFile('a.txt')
.then((data) => {
console.log('a.txt:', data);
return readFile('b.txt'); // 返回新Promise,继续链
})
.then((data) => {
console.log('b.txt:', data);
return readFile('c.txt');
})
.then((data) => console.log('c.txt:', data))
.catch((err) => console.error('出错:', err)); // 统一捕获
对比回调地狱,代码从“金字塔”变成了“直线链”!
Promise的优势
- 避免嵌套:每个then返回新Promise,可无限链式。
- 错误冒泡:一个catch捕获整条链的错误。
- 值穿透:如果then返回非Promise值,自动传递给下一个。
- 并行控制:Promise.all / Promise.race
示例:并行读取多个文件
Promise.all([readFile('a.txt'), readFile('b.txt'), readFile('c.txt')])
.then(([a, b, c]) => console.log('全部完成', a, b, c))
.catch(err => console.error(err));
书中的注意点
- Promise是“未来值”的占位符。
- then可以同步或异步执行(取决于前一个Promise状态)。
- 避免“Promise地狱”(滥用导致复杂链),但比回调好多了。
现代视角补充(2025年)
现在我们直接用原生Promise + async/await:
async function readFiles() {
try {
const a = await readFile('a.txt');
const b = await readFile('b.txt');
const c = await readFile('c.txt');
console.log(a, b, c);
} catch (err) {
console.error(err);
}
}