JavaScript 教程:深入理解 Promise 机制
什么是 Promise?
想象你是一位知名歌手,粉丝们日夜追问你新歌的发布时间。为了应对这种情况,你承诺在新歌发布时会立即通知所有订阅的粉丝。你创建了一个订阅列表,粉丝可以填写他们的邮箱地址。这样无论歌曲何时发布,所有订阅者都能第一时间收到通知。即使录音室发生火灾导致歌曲无法发布,你也会通知粉丝这个坏消息。
这个生活场景完美类比了编程中的 Promise 机制:
- 生产代码:需要时间执行的操作(如网络请求获取数据),就像歌手录制歌曲
- 消费代码:需要生产代码结果的多个函数,就像等待新歌的粉丝们
- Promise:连接生产代码和消费代码的特殊对象,就像订阅列表
Promise 的基本语法
Promise 对象的构造函数语法如下:
let promise = new Promise(function(resolve, reject) {
// 执行器代码(生产代码)
});
传入 new Promise
的函数称为执行器(executor),它会自动立即执行。执行器包含生产代码,最终会生成结果。
执行器的两个回调函数
执行器接收两个由 JavaScript 引擎提供的回调函数:
resolve(value)
:操作成功完成时调用,返回结果值reject(error)
:发生错误时调用,返回错误对象
Promise 的内部状态
Promise 对象创建后具有以下内部属性:
state
:初始为"pending"
(等待),最终变为:"fulfilled"
:当resolve
被调用时"rejected"
:当reject
被调用时
result
:初始为undefined
,最终变为:value
:当resolve(value)
被调用时error
:当reject(error)
被调用时
Promise 使用示例
成功示例
let promise = new Promise(function(resolve, reject) {
setTimeout(() => resolve("完成!"), 1000);
});
1 秒后,Promise 状态变为 "fulfilled"
,结果为 "完成!"
失败示例
let promise = new Promise(function(resolve, reject) {
setTimeout(() => reject(new Error("出错了!")), 1000);
});
1 秒后,Promise 状态变为 "rejected"
,结果为错误对象
重要特性
- 状态不可逆:Promise 状态一旦从 pending 变为 fulfilled 或 rejected,就不可再改变
- 单次结果:执行器只能调用一次
resolve
或reject
,后续调用会被忽略 - 错误对象:建议使用
Error
对象作为reject
的参数
消费 Promise:then、catch、finally
then 方法
.then
是处理 Promise 结果的主要方法:
promise.then(
function(result) { /* 处理成功结果 */ },
function(error) { /* 处理错误 */ }
);
示例:
let promise = new Promise(resolve => {
setTimeout(() => resolve("完成!"), 1000);
});
promise.then(
result => alert(result), // 1秒后显示"完成!"
error => alert(error) // 不会执行
);
catch 方法
.catch
专门处理错误情况,等同于 .then(null, errorHandler)
:
let promise = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("出错了!")), 1000);
});
promise.catch(alert); // 1秒后显示错误信息
finally 方法
.finally
类似于常规 try...catch
中的 finally
块,无论 Promise 成功与否都会执行:
new Promise((resolve, reject) => {
// 执行某些操作
})
.finally(() => {
// 总是执行的清理代码
})
.then(result => {
// 处理成功结果
})
.catch(err => {
// 处理错误
});
finally 特点:
- 不接受任何参数
- 不会处理 Promise 的结果,而是将结果传递给下一个处理程序
- 如果返回一个值,该值会被忽略
- 如果抛出错误,错误会传递给下一个错误处理程序
实际应用:loadScript 改造
让我们看一个实际的 Promise 应用示例,改造基于回调的脚本加载函数:
回调版本
function loadScript(src, callback) {
let script = document.createElement('script');
script.src = src;
script.onload = () => callback(null, script);
script.onerror = () => callback(new Error(`脚本加载失败: ${src}`));
document.head.append(script);
}
Promise 版本
function loadScript(src) {
return new Promise(function(resolve, reject) {
let script = document.createElement('script');
script.src = src;
script.onload = () => resolve(script);
script.onerror = () => reject(new Error(`脚本加载失败: ${src}`));
document.head.append(script);
});
}
使用示例
let promise = loadScript("https://example.com/script.js");
promise.then(
script => alert(`${script.src} 加载成功!`),
error => alert(`错误: ${error.message}`)
);
Promise 的优势
相比传统回调方式,Promise 具有以下优势:
- 自然顺序:先调用函数,再用
.then
处理结果 - 多次调用:可以对同一个 Promise 添加多个处理程序
- 更好的错误处理:通过链式调用统一处理错误
- 代码可读性:避免了回调地狱(callback hell)
Promise 是现代 JavaScript 异步编程的基础,后续的 async/await 语法也是基于 Promise 实现的。掌握 Promise 是成为 JavaScript 开发高手的必经之路。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考