在 JavaScript 中使用 Promise 而不是回调有什么优缺点?
主题
异步JavaScript
在GitHub上编辑
TL;DR
Promise 提供了一种比回调更简洁的替代方案,有助于避免回调地狱,并使异步代码更具可读性。它们有助于轻松编写顺序和并行的异步操作。但是,使用 Promise 可能会引入稍微复杂的代码。
优点
避免难以阅读的回调地狱。
回调地狱,也称为“厄运金字塔”,是指在代码中具有多个嵌套回调时发生的现象。这可能导致代码难以阅读、维护和调试。以下是回调地狱的示例:
function getFirstData(callback) {setTimeout(() => {callback({ id: 1, title: 'First Data' });}, 1000);}function getSecondData(data, callback) {setTimeout(() => {callback({ id: data.id, title: data.title + ' Second Data' });}, 1000);}function getThirdData(data, callback) {setTimeout(() => {callback({ id: data.id, title: data.title + ' Third Data' });}, 1000);}// Callback hellgetFirstData((data) => {getSecondData(data, (data) => {getThirdData(data, (result) => {console.log(result); // Output: {id: 1, title: "First Data Second Data Third Data"}});});});
Promise 通过为代码提供更线性和可读的结构来解决回调地狱的问题。
// Example of sequential asynchronous code using setTimeout and Promisesfunction getFirstData() {return new Promise((resolve, reject) => {setTimeout(() => {resolve({ id: 1, title: 'First Data' });}, 1000);});}function getSecondData(data) {return new Promise((resolve, reject) => {setTimeout(() => {resolve({ id: data.id, title: data.title + ' Second Data' });}, 1000);});}function getThirdData(data) {return new Promise((resolve, reject) => {setTimeout(() => {resolve({ id: data.id, title: data.title + ' Third Data' });}, 1000);});}getFirstData().then(getSecondData).then(getThirdData).then((data) => {console.log(data); // Output: {id: 1, title: "First Data Second Data Third Data"}}).catch((error) => console.error('Error:', error));
使用 .then()
轻松编写可读的顺序异步代码。
在上面的代码示例中,我们使用 .then()
方法将这些 Promise 链接在一起,从而允许代码按顺序执行。它提供了一种更简洁、更易于管理的方式来处理 JavaScript 中的异步操作。
使用 Promise.all()
轻松编写并行异步代码。
Promise.all()
和回调都可以用于编写并行异步代码。但是,Promise.all()
提供了一种更简洁、更易读的方式来处理多个 Promise,尤其是在处理复杂的异步工作流程时。
function getData1() {return new Promise((resolve, reject) => {setTimeout(() => {resolve({ id: 1, title: 'Data 1' });}, 1000);});}function getData2() {return new Promise((resolve, reject) => {setTimeout(() => {resolve({ id: 2, title: 'Data 2' });}, 1000);});}function getData3() {return new Promise((resolve, reject) => {setTimeout(() => {resolve({ id: 3, title: 'Data 3' });}, 1000);});}Promise.all([getData1(), getData2(), getData3()]).then((results) => {console.log(results); // Output: [[{ id: 1, title: 'Data 1' }, { id: 2, title: 'Data 2' }, { id: 3, title: 'Data 3' }]}).catch((error) => {console.error('Error:', error);});
使用 Promise,以下情况不会发生,这些情况存在于仅使用回调的编码中:
- 过早调用回调
- 过晚调用回调(或从不调用)
- 调用回调的次数太少或太多
- 未能传递任何必要的环境/参数
- 吞噬可能发生的任何错误/异常
缺点
- 稍微复杂的代码(有争议)。
实践
- Try implementing your own
Promise.resolve()
method,Promise.reject()
method andPromise.all()
method on GreatFrontEnd.