通过制作冰淇淋学习回调、承诺、异步/等待 🍧🍨🍦 目录 - 什么是异步 JavaScript?同步 VS 异步 -> 什么是回调?承诺 异步/等待 结论 致谢 -

2025-05-25

通过制作冰淇淋🍧🍨🍦学习回调、承诺、异步/等待

目录 -

什么是异步 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 ");
Enter fullscreen mode Exit fullscreen mode

控制台上的结果

替代文本

异步

替代文本

假设吃冰淇淋需要 2 秒,
现在,让我们测试异步系统,用 JavaScript 编写这些。

注意:别担心,我们将在本文中讨论 setTimeout() 函数。

console.log("I");

// This will be shown after 2 seconds

setTimeout(()=>{
  console.log("eat");
},2000)

console.log("Ice Cream")
Enter fullscreen mode Exit fullscreen mode

控制台上的结果

替代文本

设置

替代文本

  • 对于这个项目,你可以直接打开Codepen.io开始编写代码。或者,你也可以在 VS Code 上进行操作。

  • 打开 JavaScript 部分

  • 完成后,打开开发者控制台窗口。我们将编写代码并在控制台上查看结果。

什么是回调?

替代文本

将一个函数嵌套在另一个函数中作为参数称为回调。

回调示例 ->

替代文本

注意:别担心,例子就来了。

我们为什么要使用回调?

当执行复杂任务时,我们会将其分解成多个小步骤。为了根据时间(可选)和顺序建立这些步骤之间的关系,我们使用回调。

看看这个👇

替代文本

这些是制作冰淇淋所需的小步骤。另外要注意,步骤的顺序和时间安排至关重要。你不能只是切好水果,然后就可以享用冰淇淋了。

同时,如果上一步没有完成,就无法进入下一步。

替代文本

为了更详细地解释这一点,让我们开始我们的冰淇淋店生意

但是等等...

替代文本

我们将有两面。

  • 储藏室里会有食材[我们的后端]
  • 我们将在厨房(前端)制作冰淇淋

替代文本

让我们存储数据

现在,我们要把食材储存在一个对象里。开始吧!

替代文本

将原料储存在物体内,就像这样👇

let stocks = {
    Fruits : ["strawberry", "grapes", "banana", "apple"]
 }
Enter fullscreen mode Exit fullscreen mode

我们的其他食材在这里👇

替代文本

将它们存储在 JavaScript 对象中,像这样👇

let stocks = {
    Fruits : ["strawberry", "grapes", "banana", "apple"],
    liquid : ["water", "ice"],
    holder : ["cone", "cup", "stick"],
    toppings : ["chocolate", "peanuts"],
 };
Enter fullscreen mode Exit fullscreen mode

整个业务取决于客户的订单。然后,开始生产,然后我们供应冰淇淋。因此,我们将创建两个函数 ->

  • 命令
  • 生产

替代文本

看看这个插图👇

替代文本

让我们实现我们的功能。

注意:我们将使用箭头函数

let order = () =>{};

let production = () =>{};
Enter fullscreen mode Exit fullscreen mode

现在,让我们使用回调建立这两个函数之间的关系。参见这个👇

let order = (call_production) =>{

  call_production();
};

let production = () =>{};
Enter fullscreen mode Exit fullscreen mode

让我们做一个小测试

我们将使用 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")

};
Enter fullscreen mode Exit fullscreen mode

为了运行测试,我们将调用order函数。并将第二个名为 production 的函数作为其参数。

// name 👇 of our second function
order(production);
Enter fullscreen mode Exit fullscreen mode

控制台上的结果

替代文本

休息一下

到目前为止一切都很好,休息一下!

替代文本

清除我们的console.log

保留这些代码并删除所有内容(不要删除我们的 stocks 变量)。在第一个函数中,传递另一个参数,以便接收订单“水果名称”。

// Function 1

let order = (fruit_name, call_production) =>{

  call_production();
};

// Function 2

let production = () =>{};


// Trigger 👇

order("", production);
Enter fullscreen mode Exit fullscreen mode

这是我们的步骤,以及执行每个步骤所需的时间。

替代文本

为了建立计时部分,函数 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);
Enter fullscreen mode Exit fullscreen mode

控制台上的结果

注意: 2秒后显示结果。

替代文本

如果你好奇我们如何从库存变量中取出草莓。以下是格式如下的代码:

替代文本

不要删除任何内容。开始在我们的生产函数上写东西吧。
写下这些👇

注意:我们将使用箭头函数。

let production = () =>{

  setTimeout(()=>{
    console.log("production has started")
  },0000)

};
Enter fullscreen mode Exit fullscreen mode

结果👇

替代文本

我们将在现有的 setTimeout 函数中嵌套另一个 setTimeout 函数来切水果。像这样 👇

let production = () =>{

  setTimeout(()=>{
    console.log("production has started")


    setTimeout(()=>{
      console.log("The fruit has been chopped")
    },2000)


  },0000)
};
Enter fullscreen mode Exit fullscreen mode

结果👇

替代文本

如果您还记得的话,这是我们的步骤列表。

替代文本

让我们通过将一个函数嵌套在另一个函数中来完成冰淇淋的生产(也称为回调)

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)

};
Enter fullscreen mode Exit fullscreen mode

控制台上的结果

替代文本

感觉困惑吗?

替代文本

这被称为回调地狱。它看起来像这样👇

替代文本

有什么办法可以解决这个问题?

承诺

替代文本

发明它是为了解决回调地狱问题并更好地处理我们的任务。

休息一下

但首先,休息一下!

替代文本

这就是承诺的样子。

替代文本

让我们一起剖析承诺!

替代文本

替代文本

承诺有三种状态

  • 待处理:这是初始阶段。什么也没有发生。想象一下,你的客户正在慢慢下单。但是,还没有下单。
  • 解决:这意味着您的顾客已经收到了食物并且很高兴。
  • 拒绝:这意味着您的顾客没有收到订单并离开了餐厅。

让我们对冰淇淋的生产做出承诺。

但是等等......

替代文本

我们需要了解另外 4 件事 ->

  • 时间与工作的关系
  • Promise 链
  • 错误处理
  • .finally 处理程序

让我们开始经营冰淇淋店,并通过小步骤逐一了解它们。

时间与工作的关系

如果您还记得的话,这些就是我们制作冰淇淋所需的步骤和时间。

替代文本

为了实现这一点,让我们在 JavaScript 中创建一个变量👇

let is_shop_open = true;
Enter fullscreen mode Exit fullscreen mode

现在创建一个名为 [ order ] 的函数并传递 2 个名为 [ work, ti​​me ] 的参数

let order = ( time, work ) =>{

  }
Enter fullscreen mode Exit fullscreen mode

现在,我们要向顾客承诺,“我们将为您提供冰淇淋”就像这样 ->

let order = ( time, work ) =>{

  return new Promise( ( resolve, reject )=>{ } )

  }
Enter fullscreen mode Exit fullscreen mode

注意:我们的承诺分为两部分 ->

  • 解决 [ 冰淇淋送来 ]
  • 拒绝[顾客没有拿到冰淇淋]
let order = ( time, work ) => {

  return new Promise( ( resolve, reject )=>{

    if( is_shop_open ){

      resolve( )

    }

    else{

      reject( console.log("Our shop is closed") )

    }

  })
}
Enter fullscreen mode Exit fullscreen mode

替代文本

让我们在 [ 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") )
    }

  })
}
Enter fullscreen mode Exit fullscreen mode

现在,我们将使用新创建的函数来开始制作冰淇淋。开始吧!

// Set 👇 time here
order( 2000, ()=>console.log(`${stocks.Fruits[0]} was selected`))
//    pass a ☝️ function here to start working
Enter fullscreen mode Exit fullscreen mode

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'))
})
Enter fullscreen mode Exit fullscreen mode

结果👇

替代文本

使用相同的系统,让我们完成我们的项目👇

// 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"))
})
Enter fullscreen mode Exit fullscreen mode

结果👇

替代文本

错误处理

这用于在发生意外情况时处理错误。但首先,了解一下 Promise 周期

替代文本

替代文本

为了捕获错误,我们将变量更改为 false。

let is_shop_open = false;
Enter fullscreen mode Exit fullscreen mode

这意味着我们的商店关门了。我们不向顾客出售冰淇淋。

为了解决这个问题,我们使用了 [ .catch handler] 。就像 [ .then handler ] 一样,只有当我们最初的 Promise 被拒绝时,它才会返回一个 Promise。

这里有个小提醒——

  • [.then] 在 Promise 被解决时起作用
  • [.catch] 在承诺被拒绝时起作用

来到最底部并写下👇

注意:你之前的 .then 处理程序和 .catch 处理程序之间不应该有任何内容

.catch(()=>{
  console.log("Customer left")
})
Enter fullscreen mode Exit fullscreen mode

结果👇

替代文本

笔记 :

  • 第一条消息来自我们承诺的reject()部分
  • 第二条消息来自 .catch 处理程序

.finally() 处理程序

替代文本

有一个叫做 finally 处理程序的东西,无论我们的承诺是被解决还是被拒绝,它都会起作用。

例如:服务 0 位顾客或 100 位顾客,我们的商店将在一天结束时关闭

如果你想测试一下,请到最底部写下这些👇

.finally(()=>{
  console.log("end of day")
})
Enter fullscreen mode Exit fullscreen mode

结果👇

替代文本

大家好!欢迎使用 Async / Await!

异步/等待

替代文本

据称这是编写承诺的更好方法,并有助于保持我们的代码简单和干净。

您所要做的就是在任何常规函数前写上 [ async ] 这个词,它就会成为一个承诺。

但首先,休息一下

替代文本

让我们看看👇

替代文本

为了实现我们写下的承诺

function order(){
   return new Promise( (resolve, reject) =>{

    // Write code here
   } )
}
Enter fullscreen mode Exit fullscreen mode

现在[使用 Async / Await]

在 Async / Await 方法中,我们做出如下承诺:

//👇 the magical keyword
 async function order() {
    // Write code here
 }
Enter fullscreen mode Exit fullscreen mode

但是等等......

替代文本

你需要明白 ->

  • 尝试、捕获用法
  • 如何使用 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]
Enter fullscreen mode Exit fullscreen mode

异步/等待 -> 尝试、捕获

在这里我们按照这种格式工作

//👇 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
Enter fullscreen mode Exit fullscreen mode

注意:不要惊慌,我们接下来会讨论 [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)
  })
}
Enter fullscreen mode Exit fullscreen mode

现在,让我们首先使用 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();
Enter fullscreen mode Exit fullscreen mode

让我们在 kitchen() 调用下面添加其他工作。

console.log("doing the dishes")
console.log("cleaning the tables")
console.log("taking orders")
Enter fullscreen mode Exit fullscreen mode

结果

替代文本

我们确实会走出厨房询问顾客:“您选择的配料是什么?”与此同时,其他工作也在进行中。

一旦我们选择了配料,我们就进入厨房并完成工作。

小纸条

当使用 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"))
      }
    });
}

Enter fullscreen mode Exit fullscreen mode

现在,让我们创建我们的厨房 ->

async function kitchen(){
   try{

     // instruction here
   }

   catch(error){
    // error management here
   }
}

// Trigger
kitchen();
Enter fullscreen mode Exit fullscreen mode

让我们给出一些小说明,测试我们的厨房功能是否正常工作

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();
Enter fullscreen mode Exit fullscreen mode

结果,当商店开门时👇

替代文本

商店关门后的结果👇

替代文本

到目前为止,一切都很好 !

替代文本

让我们完成我们的项目。

这是我们的任务清单👇

替代文本

首先,开我们的店

let is_shop_open = true;
Enter fullscreen mode Exit fullscreen mode

现在按照以下步骤在我们的 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")
    }
}
Enter fullscreen mode Exit fullscreen mode

结果👇

替代文本

结论

这是你读到最后的奖牌❤️

非常感谢您的建议和批评❤️

替代文本

致谢 -

文章来源:https://dev.to/joyshaheb/learn-callbacks-promises-async-await-by-making-ice-cream-4n76
PREV
精通 CSS Flexbox 2021 🔥- 构建 5 个响应式布局🎖️|| CSS 2021 Youtube Flex-Box 架构 Flex-Box 图表设置 级别 1 级别 2 级别 3 级别 4 你赢了吗,儿子?让我们火力全开🥵 级别 5 阅读更多 结论
NEXT
2021 年,用 5 个练习轻松掌握 CSS 网格模型 || CSS 2021 🔥 YouTube 设置 🔥 级别 1 级别 2 让我们用网格模板区域改变游戏规则 😎 级别 3 级别 4 你赢了吗,儿子?让我们火力全开 🥵 级别 5 结论