Appearance
十一、Promise 异步编程
Promise 是 ES6 引入的一种处理异步操作的新方式,它可以避免回调地狱,使异步代码更加清晰易读。
回调地狱是什么?
在 ES6 之前,处理异步操作通常使用回调函数,但当多个异步操作嵌套时,会形成回调地狱:
javascript
// 回调地狱示例
fs.readFile('file1.txt', 'utf8', function(err, data1) {
if (err) throw err;
fs.readFile('file2.txt', 'utf8', function(err, data2) {
if (err) throw err;
fs.readFile('file3.txt', 'utf8', function(err, data3) {
if (err) throw err;
console.log(data1 + data2 + data3);
});
});
});这种代码难以阅读和维护,Promise 的出现就是为了解决这个问题。
Promise 基本语法
创建 Promise
javascript
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
const success = true;
if (success) {
resolve('操作成功');
} else {
reject('操作失败');
}
}, 1000);
});消费 Promise
javascript
promise
.then(result => {
console.log(result); // 操作成功
})
.catch(error => {
console.log(error); // 操作失败
});then() catch() finally()
then() 方法
then() 方法用于处理 Promise 成功的情况,它返回一个新的 Promise,所以可以链式调用。
javascript
const promise = new Promise((resolve, reject) => {
resolve(1);
});
promise
.then(value => {
console.log(value); // 1
return value * 2;
})
.then(value => {
console.log(value); // 2
return value * 2;
})
.then(value => {
console.log(value); // 4
});catch() 方法
catch() 方法用于处理 Promise 失败的情况。
javascript
const promise = new Promise((resolve, reject) => {
reject('出错了');
});
promise
.then(result => {
console.log(result);
})
.catch(error => {
console.log(error); // 出错了
});finally() 方法
finally() 方法无论 Promise 成功还是失败都会执行。
javascript
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功');
}, 1000);
});
promise
.then(result => {
console.log(result); // 成功
})
.catch(error => {
console.log(error);
})
.finally(() => {
console.log('操作完成'); // 无论成功失败都会执行
});Promise.all() 并发请求
Promise.all() 方法接收一个 Promise 数组,只有当所有 Promise 都成功时才会成功,否则失败。
javascript
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('第一个请求成功'), 1000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => resolve('第二个请求成功'), 2000);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => resolve('第三个请求成功'), 1500);
});
Promise.all([promise1, promise2, promise3])
.then(results => {
console.log(results); // ['第一个请求成功', '第二个请求成功', '第三个请求成功']
})
.catch(error => {
console.log(error);
});Promise.race()
Promise.race() 方法接收一个 Promise 数组,只要有一个 Promise 完成(成功或失败),就会返回那个 Promise 的结果。
javascript
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('第一个请求成功'), 1000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => resolve('第二个请求成功'), 500);
});
Promise.race([promise1, promise2])
.then(result => {
console.log(result); // 第二个请求成功(因为它更快)
});实战:模拟接口请求
javascript
// 模拟 API 请求
function fetchData(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(`Fetching data from ${url}`);
resolve(`Data from ${url}`);
}, 1000);
});
}
// 顺序请求
fetchData('https://api.example.com/users')
.then(data => {
console.log(data);
return fetchData('https://api.example.com/posts');
})
.then(data => {
console.log(data);
return fetchData('https://api.example.com/comments');
})
.then(data => {
console.log(data);
console.log('All requests completed');
});
// 并发请求
Promise.all([
fetchData('https://api.example.com/users'),
fetchData('https://api.example.com/posts'),
fetchData('https://api.example.com/comments')
])
.then(results => {
console.log(results);
console.log('All requests completed');
});异步流程优雅写法
传统回调 vs Promise
javascript
// 传统回调
function getData(callback) {
setTimeout(() => {
callback('数据');
}, 1000);
}
getData(data => {
console.log(data);
});
// Promise
function getData() {
return new Promise(resolve => {
setTimeout(() => {
resolve('数据');
}, 1000);
});
}
getData().then(data => {
console.log(data);
});多个异步操作
javascript
// 传统回调
function step1(callback) {
setTimeout(() => {
callback('步骤1完成');
}, 1000);
}
function step2(data, callback) {
setTimeout(() => {
callback(`${data}, 步骤2完成`);
}, 1000);
}
function step3(data, callback) {
setTimeout(() => {
callback(`${data}, 步骤3完成`);
}, 1000);
}
step1(data1 => {
step2(data1, data2 => {
step3(data2, data3 => {
console.log(data3); // 步骤1完成, 步骤2完成, 步骤3完成
});
});
});
// Promise
function step1() {
return new Promise(resolve => {
setTimeout(() => {
resolve('步骤1完成');
}, 1000);
});
}
function step2(data) {
return new Promise(resolve => {
setTimeout(() => {
resolve(`${data}, 步骤2完成`);
}, 1000);
});
}
function step3(data) {
return new Promise(resolve => {
setTimeout(() => {
resolve(`${data}, 步骤3完成`);
}, 1000);
});
}
step1()
.then(step2)
.then(step3)
.then(data => {
console.log(data); // 步骤1完成, 步骤2完成, 步骤3完成
});Promise 的优势
- 避免回调地狱:使异步代码更加清晰易读
- 链式调用:可以方便地处理多个异步操作
- 错误处理:统一的错误处理机制
- 并发处理:支持多个异步操作的并发执行
- 与 async/await 配合:为 async/await 提供基础
通过本章节的学习,你已经掌握了 Promise 的基本用法和优势。Promise 是 ES6 中处理异步操作的重要特性,它使异步代码更加优雅和可维护。
