通过制作冰淇淋🍧🍨🍦学习回调、承诺、异步/等待
目录 -
什么是异步 JavaScript?
同步 VS 异步 ->
什么是回调?
承诺
异步/等待
结论
致谢 -
今天我们要经营一家冰淇淋店,并学习异步 JS。在此过程中,我们将了解如何使用
- 回调
- 承诺
- 异步/等待
目录 -
- 什么是异步 JavaScript
- 同步 JavaScript 与异步 JavaScript
- 回调
- 承诺
- 异步/等待
- 结论
如果您愿意,也可以在 YouTube 上观看本教程
什么是异步 JavaScript?
如果您想高效地构建项目,那么这适合您。
异步 javascript 理论可以帮助您将复杂且大型的项目分解为较小的任务。
然后,使用这三种技术中的任何一种(回调、承诺或异步/等待),我们以一种获得最终结果的方式运行这些小任务
让我们开始吧!🎖️
同步 VS 异步 ->
同步系统
在这个系统中,任务是一个接一个地完成的。
想象一下,你只有一只手来完成10项任务。所以,你必须一次完成一项任务。
看一下 GIF 👇

您会注意到,如果第一幅图像没有完全加载,第二幅图像就不会加载。
笔记 :
默认情况下,JavaScript 是同步的[单线程]这样想,1 个线程意味着 1 只手
异步系统
在这个系统中,任务是独立完成的。
假设有 10 项任务,你需要 10 只手。所以每只手都可以独立完成任务。
看一下 GIF 👇

你会注意到,所有图片都在按自己的节奏加载。没有人在等待别人。
总结一下 -
当 3 张图片在马拉松比赛中时,在 ->
- 同步:3 张图片位于同一车道。禁止超车。比赛按顺序完成。如果 3 号图片停止,则所有图片停止。
- 异步:3 张图片位于不同的赛道上。它们将按照各自的节奏完成比赛。没有人会为其他人停车
示例
在开始我们的项目之前,让我们先看一些例子并消除疑虑。
同步
要测试同步系统,请在 JavaScript 上编写这些内容
console.log(" I ");
console.log(" eat ");
console.log(" Ice Cream ");
控制台上的结果
异步
假设吃冰淇淋需要 2 秒,
现在,让我们测试异步系统,用 JavaScript 编写这些。
注意:别担心,我们将在本文中讨论 setTimeout() 函数。
console.log("I");
// This will be shown after 2 seconds
setTimeout(()=>{
console.log("eat");
},2000)
console.log("Ice Cream")
控制台上的结果
设置
-
对于这个项目,你可以直接打开Codepen.io开始编写代码。或者,你也可以在 VS Code 上进行操作。
-
打开 JavaScript 部分
-
完成后,打开开发者控制台窗口。我们将编写代码并在控制台上查看结果。
什么是回调?
将一个函数嵌套在另一个函数中作为参数称为回调。
回调示例 ->
注意:别担心,例子就来了。
我们为什么要使用回调?
当执行复杂任务时,我们会将其分解成多个小步骤。为了根据时间(可选)和顺序建立这些步骤之间的关系,我们使用回调。
看看这个👇
这些是制作冰淇淋所需的小步骤。另外要注意,步骤的顺序和时间安排至关重要。你不能只是切好水果,然后就可以享用冰淇淋了。
同时,如果上一步没有完成,就无法进入下一步。
为了更详细地解释这一点,让我们开始我们的冰淇淋店生意
但是等等...
我们将有两面。
- 储藏室里会有食材[我们的后端]
- 我们将在厨房(前端)制作冰淇淋
让我们存储数据
现在,我们要把食材储存在一个对象里。开始吧!
将原料储存在物体内,就像这样👇
let stocks = {
Fruits : ["strawberry", "grapes", "banana", "apple"]
}
我们的其他食材在这里👇
将它们存储在 JavaScript 对象中,像这样👇
let stocks = {
Fruits : ["strawberry", "grapes", "banana", "apple"],
liquid : ["water", "ice"],
holder : ["cone", "cup", "stick"],
toppings : ["chocolate", "peanuts"],
};
整个业务取决于客户的订单。然后,开始生产,然后我们供应冰淇淋。因此,我们将创建两个函数 ->
- 命令
- 生产
看看这个插图👇
让我们实现我们的功能。
注意:我们将使用箭头函数
let order = () =>{};
let production = () =>{};
现在,让我们使用回调建立这两个函数之间的关系。参见这个👇
let order = (call_production) =>{
call_production();
};
let production = () =>{};
让我们做一个小测试
我们将使用 console.log() 函数进行测试,以消除我们对如何建立这两个函数之间的关系的疑虑。
let order = (call_production) =>{
console.log("Order placed. Please call production")
// function 👇 is being called
call_production();
};
let production = () =>{
console.log("Production has started")
};
为了运行测试,我们将调用order函数。并将第二个名为 production 的函数作为其参数。
// name 👇 of our second function
order(production);
控制台上的结果
休息一下
到目前为止一切都很好,休息一下!
清除我们的console.log
保留这些代码并删除所有内容(不要删除我们的 stocks 变量)。在第一个函数中,传递另一个参数,以便接收订单“水果名称”。
// Function 1
let order = (fruit_name, call_production) =>{
call_production();
};
// Function 2
let production = () =>{};
// Trigger 👇
order("", production);
这是我们的步骤,以及执行每个步骤所需的时间。
为了建立计时部分,函数 setTimeout() 非常棒,因为它还通过将函数作为参数来使用回调。
现在,让我们选择水果。
// 1st Function
let order = (fruit_name, call_production) =>{
setTimeout(function(){
console.log(`${stocks.Fruits[fruit_name]} was selected`)
// Order placed. Call production to start
call_production();
},2000)
};
// 2nd Function
let production = () =>{
// blank for now
};
// Trigger 👇
order(0, production);
控制台上的结果
注意: 2秒后显示结果。
如果你好奇我们如何从库存变量中取出草莓。以下是格式如下的代码:
不要删除任何内容。开始在我们的生产函数上写东西吧。
写下这些👇
注意:我们将使用箭头函数。
let production = () =>{
setTimeout(()=>{
console.log("production has started")
},0000)
};
结果👇
我们将在现有的 setTimeout 函数中嵌套另一个 setTimeout 函数来切水果。像这样 👇
let production = () =>{
setTimeout(()=>{
console.log("production has started")
setTimeout(()=>{
console.log("The fruit has been chopped")
},2000)
},0000)
};
结果👇
如果您还记得的话,这是我们的步骤列表。
让我们通过将一个函数嵌套在另一个函数中来完成冰淇淋的生产(也称为回调)
let production = () =>{
setTimeout(()=>{
console.log("production has started")
setTimeout(()=>{
console.log("The fruit has been chopped")
setTimeout(()=>{
console.log(`${stocks.liquid[0]} and ${stocks.liquid[1]} Added`)
setTimeout(()=>{
console.log("start the machine")
setTimeout(()=>{
console.log(`Ice cream placed on ${stocks.holder[1]}`)
setTimeout(()=>{
console.log(`${stocks.toppings[0]} as toppings`)
setTimeout(()=>{
console.log("serve Ice cream")
},2000)
},3000)
},2000)
},1000)
},1000)
},2000)
},0000)
};
控制台上的结果
感觉困惑吗?
这被称为回调地狱。它看起来像这样👇
有什么办法可以解决这个问题?
承诺
发明它是为了解决回调地狱问题并更好地处理我们的任务。
休息一下
但首先,休息一下!
这就是承诺的样子。
让我们一起剖析承诺!
承诺有三种状态
- 待处理:这是初始阶段。什么也没有发生。想象一下,你的客户正在慢慢下单。但是,还没有下单。
- 解决:这意味着您的顾客已经收到了食物并且很高兴。
- 拒绝:这意味着您的顾客没有收到订单并离开了餐厅。
让我们对冰淇淋的生产做出承诺。
但是等等......
我们需要了解另外 4 件事 ->
- 时间与工作的关系
- Promise 链
- 错误处理
- .finally 处理程序
让我们开始经营冰淇淋店,并通过小步骤逐一了解它们。
时间与工作的关系
如果您还记得的话,这些就是我们制作冰淇淋所需的步骤和时间。
为了实现这一点,让我们在 JavaScript 中创建一个变量👇
let is_shop_open = true;
现在创建一个名为 [ order ] 的函数并传递 2 个名为 [ work, time ] 的参数
let order = ( time, work ) =>{
}
现在,我们要向顾客承诺,“我们将为您提供冰淇淋”就像这样 ->
let order = ( time, work ) =>{
return new Promise( ( resolve, reject )=>{ } )
}
注意:我们的承诺分为两部分 ->
- 解决 [ 冰淇淋送来 ]
- 拒绝[顾客没有拿到冰淇淋]
let order = ( time, work ) => {
return new Promise( ( resolve, reject )=>{
if( is_shop_open ){
resolve( )
}
else{
reject( console.log("Our shop is closed") )
}
})
}
让我们在 [ if 语句 ] 中使用 [ setTimeout() ] 函数,在 Promise 中添加时间和工作量。关注我 👇
注意:在现实生活中,你也可以避免时间因素。这完全取决于你的工作性质。
let order = ( time, work ) => {
return new Promise( ( resolve, reject )=>{
if( is_shop_open ){
setTimeout(()=>{
// work is 👇 getting done here
resolve( work() )
// Setting 👇 time here for 1 work
}, time)
}
else{
reject( console.log("Our shop is closed") )
}
})
}
现在,我们将使用新创建的函数来开始制作冰淇淋。开始吧!
// Set 👇 time here
order( 2000, ()=>console.log(`${stocks.Fruits[0]} was selected`))
// pass a ☝️ function here to start working
2秒后的结果👇
好工作 !
Promise 链
在这个方法中,我们使用 [ .then handler ] 定义了第一个任务完成后要做什么。它看起来像这样👇
当我们最初的承诺得到解决时,[ .then handler ] 将返回一个承诺。
例子 :
简单来说,这就像给某人下达指令。你告诉某人“先做这个,然后做这个,然后这个,然后……,然后……,然后……”等等。
- 第一项任务是我们[最初的]承诺。
- 其余的人在完成一项小工作后就归还我们的承诺
让我们在项目中实现它。在底部写下这些。👇
注意:别忘了在 [ .then 处理程序 ] 中写上 [ return ] 字样,否则会无法正常工作。如果您感兴趣,请在我们完成这些步骤后尝试删除 [ return ] 字样。
order(2000,()=>console.log(`${stocks.Fruits[0]} was selected`))
.then(()=>{
return order(0000,()=>console.log('production has started'))
})
结果👇
使用相同的系统,让我们完成我们的项目👇
// step 1
order(2000,()=>console.log(`${stocks.Fruits[0]} was selected`))
// step 2
.then(()=>{
return order(0000,()=>console.log('production has started'))
})
// step 3
.then(()=>{
return order(2000, ()=>console.log("Fruit has been chopped"))
})
// step 4
.then(()=>{
return order(1000, ()=>console.log(`${stocks.liquid[0]} and ${stocks.liquid[1]} added`))
})
// step 5
.then(()=>{
return order(1000, ()=>console.log("start the machine"))
})
// step 6
.then(()=>{
return order(2000, ()=>console.log(`ice cream placed on ${stocks.holder[1]}`))
})
// step 7
.then(()=>{
return order(3000, ()=>console.log(`${stocks.toppings[0]} as toppings`))
})
// Step 8
.then(()=>{
return order(2000, ()=>console.log("Serve Ice Cream"))
})
结果👇
错误处理
这用于在发生意外情况时处理错误。但首先,了解一下 Promise 周期
为了捕获错误,我们将变量更改为 false。
let is_shop_open = false;
这意味着我们的商店关门了。我们不向顾客出售冰淇淋。
为了解决这个问题,我们使用了 [ .catch handler] 。就像 [ .then handler ] 一样,只有当我们最初的 Promise 被拒绝时,它才会返回一个 Promise。
这里有个小提醒——
- [.then] 在 Promise 被解决时起作用
- [.catch] 在承诺被拒绝时起作用
来到最底部并写下👇
注意:你之前的 .then 处理程序和 .catch 处理程序之间不应该有任何内容
.catch(()=>{
console.log("Customer left")
})
结果👇
笔记 :
- 第一条消息来自我们承诺的reject()部分
- 第二条消息来自 .catch 处理程序
.finally() 处理程序
有一个叫做 finally 处理程序的东西,无论我们的承诺是被解决还是被拒绝,它都会起作用。
例如:服务 0 位顾客或 100 位顾客,我们的商店将在一天结束时关闭
如果你想测试一下,请到最底部写下这些👇
.finally(()=>{
console.log("end of day")
})
结果👇
大家好!欢迎使用 Async / Await!
异步/等待
据称这是编写承诺的更好方法,并有助于保持我们的代码简单和干净。
您所要做的就是在任何常规函数前写上 [ async ] 这个词,它就会成为一个承诺。
但首先,休息一下
让我们看看👇
前
为了实现我们写下的承诺
function order(){
return new Promise( (resolve, reject) =>{
// Write code here
} )
}
现在[使用 Async / Await]
在 Async / Await 方法中,我们做出如下承诺:
//👇 the magical keyword
async function order() {
// Write code here
}
但是等等......
你需要明白 ->
- 尝试、捕获用法
- 如何使用 Await 关键字
Try、Catch 用法
[ Try ] 关键字用于运行代码,[ catch ] 用于捕获错误。它的概念和我们在 Promise 中看到的概念相同。
让我们看一下比较
注意:我们将看到格式的一个小演示,然后我们将开始编码
承诺 -> 解决,拒绝
我们在 Promise 中使用了 resolve 和 rejection,像这样 ->
function kitchen(){
return new Promise ((resolve, reject)=>{
if(true){
resolve("promise is fulfilled")
}
else{
reject("error caught here")
}
})
}
kitchen() // run the code
.then() // next step
.then() // next step
.catch() // error caught here
.finally() // end of the promise [optional]
异步/等待 -> 尝试、捕获
在这里我们按照这种格式工作
//👇 Magical keyword
async function kitchen(){
try{
// Let's create a fake problem
await abc;
}
catch(error){
console.log("abc does not exist", error)
}
finally{
console.log("Runs code anyways")
}
}
kitchen() // run the code
注意:不要惊慌,我们接下来会讨论 [await 关键字]
你会注意到,promises、Async/Await 之间的区别
Await关键字的用法
关键字 [await] 使 JavaScript 等待直到该承诺解决并返回其结果。
一个实际的例子
我们不知道顾客喜欢哪种配料,巧克力还是花生?
我们得关掉机器,走过去问顾客:“先生,您想加什么配料?”
注意这里,只有我们的厨房停止了,但是厨房外的工作人员仍然会像
- 洗碗
- 清洁桌子
- 接受订单等
代码示例
让我们创建一个小承诺,询问使用哪种配料。该过程需要 3 秒。
function toppings_choice (){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve( console.log("which topping would you love?") )
},3000)
})
}
现在,让我们首先使用 async 关键字创建我们的厨房功能。
async function kitchen(){
console.log("A")
console.log("B")
console.log("C")
await toppings_choice()
console.log("D")
console.log("E")
}
// Trigger the function
kitchen();
让我们在 kitchen() 调用下面添加其他工作。
console.log("doing the dishes")
console.log("cleaning the tables")
console.log("taking orders")
结果
我们确实会走出厨房询问顾客:“您选择的配料是什么?”与此同时,其他工作也在进行中。
一旦我们选择了配料,我们就进入厨房并完成工作。
小纸条
当使用 Async/Await 时,您还可以使用 [ .then, .catch, .finally ] 处理程序,它们是承诺的核心部分。
让我们再次开冰淇淋店
我们将创建两个函数 ->
- 厨房:制作冰淇淋
- 时间:分配完成每个小任务所需的时间。
开始吧!首先,创建时间函数 ->
let is_shop_open = true;
function time(ms) {
return new Promise( (resolve, reject) => {
if(is_shop_open){
setTimeout(resolve,ms);
}
else{
reject(console.log("Shop is closed"))
}
});
}
现在,让我们创建我们的厨房 ->
async function kitchen(){
try{
// instruction here
}
catch(error){
// error management here
}
}
// Trigger
kitchen();
让我们给出一些小说明,测试我们的厨房功能是否正常工作
async function kitchen(){
try{
// time taken to perform this 1 task
await time(2000)
console.log(`${stocks.Fruits[0]} was selected`)
}
catch(error){
console.log("Customer left", error)
}
finally{
console.log("Day ended, shop closed")
}
}
// Trigger
kitchen();
结果,当商店开门时👇
商店关门后的结果👇
到目前为止,一切都很好 !
让我们完成我们的项目。
这是我们的任务清单👇
首先,开我们的店
let is_shop_open = true;
现在按照以下步骤在我们的 kitchen() 函数中编写步骤👇
async function kitchen(){
try{
await time(2000)
console.log(`${stocks.Fruits[0]} was selected`)
await time(0000)
console.log("production has started")
await time(2000)
console.log("fruit has been chopped")
await time(1000)
console.log(`${stocks.liquid[0]} and ${stocks.liquid[1]} added`)
await time(1000)
console.log("start the machine")
await time(2000)
console.log(`ice cream placed on ${stocks.holder[1]}`)
await time(3000)
console.log(`${stocks.toppings[0]} as toppings`)
await time(2000)
console.log("Serve Ice Cream")
}
catch(error){
console.log("customer left")
}
}
结果👇
结论
这是你读到最后的奖牌❤️
非常感谢您的建议和批评❤️
-
YouTube /乔伊·沙希布
-
LinkedIn /JoyShaheb
-
Twitter /JoyShaheb
-
Instagram /JoyShaheb