引言:异步编程的"前世今生"
作为前端开发者,你是否也曾面对这样的代码?
// 回调地狱示例
setTimeout(() => {
console.log('第一层');
setTimeout(() => {
console.log('第二层');
setTimeout(() => {
console.log('第三层');
// ...无尽嵌套
}, 1000);
}, 1000);
}, 1000);
这种"回调地狱"不仅可读性差,维护更是噩梦。ES6的Promise正是为解决异步流程控制而生,它让异步代码变得线性、可预测
一、Promise基础:认识异步承诺
1.1 Promise是什么?
Promise是一个 异步操作的容器 ,它代表了一个最终可能完成(或失败)的异步操作及其结果值。想象成你点外卖:下单(创建Promise)→制作中(pending)→送达(fulfilled)/取消(rejected)。
1.2 基本语法
// 创建Promise实例
const p = new Promise((resolve) => {
console.log('3333'); // 同步执行
setTimeout(() => {
console.log('2222');
resolve(); // 异步操作完成后调用
}, 10);
});
// 通过then处理结果
p.then(() => {
console.log('1111');
});
执行顺序:3333 → 2222 → 1111,完美解决了异步代码的执行顺序问题
1.3 三种状态
- pending :初始状态,既不是成功也不是失败
- fulfilled :操作成功完成,调用resolve()
- rejected :操作失败,调用reject()
注意:Promise状态一旦改变就不可逆!就像泼出去的水,无法收回
二、核心方法:then的链式魔法
2.1 基础用法
Promise实例的 then 方法用于注册回调函数,处理成功状态的值:
// 文件读取示例
const fs = require('fs');
const readFilePromise = new Promise((resolve) => {
fs.readFile('./1.html', (err, data) => {
console.log(data.toString());
resolve(); // 读取完成后触发then
});
});
readFilePromise.then(() => {
console.log('读完啦======');
});
2.2 链式调用
then 方法会返回一个新的Promise,这让链式调用成为可能:
fetchData()
.then(data => process(data))
.then(result => display(result))
.then(() => console.log('完成'));
每个then都接收前一个then的返回值,形成清晰的流水线。
三、语法糖:async/await让异步变同步
ES2017引入的async/await是Promise的语法糖,让异步代码看起来像同步代码:
3.1 基本用法
(async function(){
const p = new Promise((resolve) => {
setTimeout(() => {
resolve('success');
}, 1000);
});
const res = await p; // 等待Promise完成
console.log(res); // success
console.log('111111');
})();
3.2 实战案例:GitHub API请求
document.addEventListener('DOMContentLoaded', async () => {
const res = await fetch('https://api.github.com/users/NFkenny/repos');
const data = await res.json(); // 链式await
document.getElementById('repos').innerHTML = data.map(item => {
return `<li><a href="${item.html_url}" target="_blank">${item.name}</a></li>`
}).join('');
});
四、常见陷阱与最佳实践
4.1 错误处理
// 使用catch捕获错误
fetchData()
.then(processData)
.catch(error => {
console.error('出错啦:', error);
});
// async/await中使用try-catch
async function loadData() {
try {
const data = await fetchData();
} catch (error) {
console.error(error);
}
}
4.2 并行处理
// 使用Promise.all处理并行任务
Promise.all([
fetchUserInfo(),
fetchOrderList(),
fetchProductList()
]).then(([user, orders, products]) => {
// 所有请求都完成后执行
});
五、Promise的哲学启示
通过上述示例我们可以发现:
- Promise将异步操作 对象化 ,让流程控制更直观
- then方法实现了 责任链模式 ,每个环节专注单一职责
- async/await是 语法层面的抽象 ,底层仍是Promise机制
这种设计哲学深刻影响着现代前端架构,从Redux的状态管理到微前端通信机制,都能看到Promise思想的延伸。其核心价值在于: 用确定性的语法结构驾驭不确定性的异步世界 。