从回调、Promise到async/await:详解JavaScript异步编程终极指南
学习使用回调、Promise 和 async/await 进行 JavaScript 异步编程,避免回调地狱,通过实际例子编写更简洁、更易维护的代码。
大家好,各位前端开发者们,今天咱们来聊聊javascript里头一个超级重要的概念:异步编程的概念。
- 我将在Scribbler.live上首先创建我的代码片段,这是一个非常棒的平台,可以让你无需手动设置就能运行JavaScript笔记本、在线编译器和编辑器。
- 此外,我还将提供一个链接,该链接包含所有代码示例,你可以直接打开并运行代码片段来自行查看结果。
- 我将使用
scrib.show
,这是来自Scribbler.live的一个功能,它类似于JavaScript中的console.log
。
咱们直接来吧
目录:
-
什么是回调
-
基本示例
-
异步回调
-
回调地狱
-
Promise
-
基本示例
-
获取数据
-
Promise链式调用
-
Promise方法(如then、catch等)
-
async await
-
解决回调地狱
- 获取数据
- 回调函数是指将一个函数作为参数传递给另一个函数,该函数随后会被执行(同步或异步),
- 回调函数在JavaScript中用于处理异步任务、事件处理和函数式编程。
代码示例
基本例子
function saveOrder(orderId, userMail, callback) {
const order = {
orderId,
userMail
}
scrib.show(order)
callback(userMail); // 调用回调函数
}
function sendOrderEmail(userMail) {
scrib.show(userMail, "确认订单")
}
saveOrder("145908275","user@gmail.com", sendOrderEmail);
// 这会记录订单并发送确认邮件给用户
全屏 退出全屏
异步回调
可以举例来说 setTimeout
方法,比如说它执行时是异步的。
console.log("JavaScript 很酷");
setTimeout(() => {
console.log("这段代码会在2秒后执行");
}, 2000);
console.log("Scribbler 很酷");
// 输出结果
JavaScript 很酷
Scribbler 很酷
这段代码会在2秒后执行
进入全屏 退出全屏
回调地狱(灾难金字塔)
function saveOrder(orderId, userMail, callback) {
const order = {
orderId,
userMail
}
scrib.show(order)
callback(userMail); // 执行回调
}
function sendDetailsToSeller(orderId, userMail, callback) {
const details = {
orderId,
userMail
}
scrib.show(details)
callback(userMail);
}
function sendOrderEmail(userMail) {
scrib.show(userMail, "您的订单已确认")
}
saveOrder("145908275", "user@gmail.com", () => sendDetailsToSeller("145908275", "user@gmail.com", sendOrderEmail));
// 可以看到,我们需要在多个层级传递回调以实现链式操作。
全屏 退出全屏
- 当回调嵌套层次过深时,代码就会变得很难看懂和管理了。
🔴 问题:难以阅读、维护和调试,
✅ 解决方案:Promise 或 async/await.
- 在 JavaScript 中,Promise 表示异步操作未来的结果,即成功或失败。它提供了一种比传统回调更清晰的方式来处理异步任务。
-
它接受一个有两个参数的函数:
-
resolve → 当异步任务成功时调用。
- reject → 当异步任务失败时调用。
-
Promise 状态:一个 Promise 可以处于以下三种状态之一:
-
Pending 状态 → 初始状态,既未完成也未拒绝。
-
Fulfilled 状态 → 操作成功完成。
- Rejected 状态 → 操作失败完成。
示例代码:
基本例子
const basicPromise = new Promise((resolve, reject) => {
setTimeout(() => {
let success = true; // 模拟任务的成功或失败
if (success) {
resolve("任务完成成功啦!✅");
} else {
reject("任务失败了 ❌");
}
}, 2000);
});
basicPromise
.then((result) => {
scrib.show(result); // 显示: 任务完成成功啦!✅
})
.catch((error) => {
scrib.show(error); // 显示: 任务失败了 ❌ (如果失败)
})
.finally(() => {
scrib.show("Promise 执行完了。");
});
切换到全屏 退出全屏
使用 fetch 抓取数据
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP 错误!状态码为:${response.status}`);
}
return response.json();
})
.then(data => console.log(data))
.catch(error => console.log("抓取失败:", error));
点击进入全屏 点击退出全屏
链式调用
// 使用 then 方法链式调用来处理异步操作
new Promise((resolve) => {
setTimeout(() => resolve(10), 1000);
})
.then((num) => {
scrib.show(num); // 打印数字: 10
return num * 2;
})
.then((num) => {
scrib.show(num); // 打印数字: 20
return num * 3;
})
.then((num) => {
scrib.show(num); // 打印数字: 60
});
切换到全屏,退出全屏
Promise 对象的方法
Promise.all
- 等待所有 promises 都完成解析。如果有任何一个被拒绝,整个结果也会被拒绝。Promise.race
- 返回最先完成(解析或拒绝)的 promise。Promise.allSettled
- 等待所有 promises 完成(解析或拒绝),然后返回它们的状态。Promise.any
- 返回最先被解析成功的 promise,忽略拒绝的情况。
const promise1 = new Promise((resolve) => {
setTimeout(() => resolve(Math.floor(3.14)), 1000);
})
const promise2 = new Promise((resolve) => {
setTimeout(() => resolve(Math.ceil(3.14)), 1000);
})
const promise3 = new Promise((resolve) => {
setTimeout(() => resolve(Math.pow(3.14, 10)), 1000);
})
// Promise.all
const promiseAll = Promise.all([promise1,promise2,promise3])
promiseAll.then(scrib.show())
// Promise.race
const promiseRace = Promise.race([promise1,promise2,promise3])
promiseRace.then(scrib.show())
// Promise.allSettled
const promiseAllSettled = Promise.allSettled([promise1,promise2,promise3])
promiseAllSettled.then(scrib.show())
// Promise.any
const promiseAny = Promise.any([promise1,promise2,promise3])
promiseAny.then(scrib.show())
切换到全屏 恢复正常视图
- 为了更好地处理异步,可以使用 async/await,这使得处理 Promise 更加简单。
async/await
是现代 JavaScript 的一个特性,简化了处理异步代码。它允许你以同步代码的方式编写异步代码,使其更易于阅读、理解和调试。-
为什么要用 async/await 呢?
-
在 async/await 之前,JavaScript 开发者处理异步代码的方法包括:
-
回调(导致回调地狱)
-
Promise(虽然更好,但仍需要使用
.then()
来链接处理程序) async/await
的工作原理 - 标记为 async 的函数会自动返回一个 Promise,即使它返回的是一个简单的值也一样。
示例代码
解决回调地狱
// 异步 await 示例,解决回调地狱问题
async function saveOrder(orderId, userMail) {
const order = {
orderId,
userMail
}
scrib.show(order)
return order
}
async function sendDetailsToSeller(orderId, userMail) {
const details = {
orderId,
userMail
}
scrib.show(details)
return details
}
async function sendOrderEmail(userMail) {
scrib.show(userMail, "Order confirmed")
return "Email sent"
}
async function processOrder(orderId, userMail) {
await saveOrder(orderId, userMail);
await sendDetailsToSeller(orderId, userMail);
await sendOrderEmail(userMail);
}
processOrder("145908275","user@gmail.com");
// 这样读起来更清晰,也更容易管理
进入全屏,退出全屏
数据抓取:
// 使用 async/await 获取数据
async function fetchData() {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1'); // ✅ 等待 fetch 请求完成
if (!response.ok) {
throw new Error(`HTTP 错误!状态码:${response.status},请检查网络。`);
}
const data = await response.json(); // ✅ 等待 response.json()
return data;
}
fetchData()
.then(data => scrib.show("获取的数据如下:", data))
.catch(error => scrib.show("错误信息:", error));
点击此处进入/退出全屏模式
使用 async/await 和循环来处理可读流
// 以下代码示例展示如何结合异步/await与循环来获取待办事项数据
async function 获取待办事项() {
let url列表 = [
"https://jsonplaceholder.typicode.com/todos/1",
"https://jsonplaceholder.typicode.com/todos/2",
"https://jsonplaceholder.typicode.com/todos/3"
];
for (let url of url列表) {
let response = await fetch(url);
let data = await response.json();
// 将数据展示出来
scrib.show(data);
}
}
获取待办事项();
进入全屏 / 退出全屏
试试这个嵌入,运行上面提到的代码示例。
这篇帖子到这就结束了,如果文章还有需要改进的地方,请告诉我。也来看看Scribbler.live网站吧。
你可以联系我:Instagram - Instagram:https://www.instagram.com/supremacism__shubh/
LinkedIn - LinkedIn:https://www.linkedin.com/in/shubham-tiwari-b7544b193/
邮箱 - shubhmtiwri00@gmail.com
下面的链接是我收款的地方,感谢你的支持👇👇
https://www.buymeacoffee.com/waaduheck
也别忘了看看这些帖子。
## 带 CVA 和 Tailwind 的按钮组件文章 Shubham Tiwari · 发布 2024年2月12日 #nextjs #react #webdev #typescript
08:22
## 微前端技术 - React | Solid | Vue Tiwari Shubham · 2024年1月9日 #教程指南 #webdev #新手 #学习之路
15:48
## Codium | 开发者的AI助手Codium Shubham Tiwari ・ 2024年1月4日 #vscode #提升 #指南 #新手
05:25
## Zustand - 初学者指南 Shubham Tiwari ・ 2023年11月21日 #webdev #教程 #React #JavaScript
共同学习,写下你的评论
暂无评论
作者其他优质文章