JavaScript Async/Await 教程
今天我们将通过建立并运行一个冰淇淋店来学习异步 JavaScript。在此过程中,你将学习如何使用:
Callbacks
Promises
Async / Await
我们将在本文中介绍以下内容:
什么是异步 JavaScript
JavaScript 中的同步与异步
Callbacks 如何在 JavaScript 中运行
Promises 如何在 JavaScript 中运行
Async/Await 如何在 JavaScript 中运行
让我们开始吧!
什么是异步 JavaScript?
如果你想高效地构建项目,那么这个概念很适合你。
异步 JavaScript 理论可以帮助你将大型复杂的项目分解为较小的任务。
然后你可以使用 callbacks、promises 或 Async/await 中的任何一种来运行这些小任务,获得最好的结果。
让我们开始吧!🎖️
JavaScript 中的同步和异步
什么是同步系统?
在同步系统中,任务一个接一个地完成。
想象一下,如果你只有一只手去完成十项任务,那么在同一个时间你只能做一个任务。
看看这个动图 – 这里会发生一件事:
你将看到,直到第一个图像完全加载,第二个图像才开始加载。
JavaScript 默认是同步的 [单线程]。你可以这样想 ——— 单线程意味着一次只能做一件事。
什么是异步系统?
在这个系统中,任务是独立完成的。
假设你有十个任务以及十只手,那么在同一时间,每只手都可以同时独立完成每一项任务。
看看这张动图 - 你可以看到每个图像都是同时加载的。
同样,所有的图像都以自己的速度加载,它们都不会等待其他任务先完成。
总结一下同步 JS 和异步 JS
想象三张图片在跑马拉松,在一个:
同步 系统,三张图片在同一条跑道上,一个不能超过另外一个,比赛得一个接一个地完成,如果 2 号图像停止,后续的图片也会停止。
异步 系统,这三张图片在不同的跑道上,它们会在自己的跑道上完成比赛,不会受其他图片的影响:
同步和异步代码示例
在开始我们的项目之前,让我们看一些例子来消除一些疑问。
同步的代码示例
为了测试同步系统,用 JavaScript 写以下代码:
控制台的结果如下:
异步代码示例
我们假设吃冰淇淋需要两秒钟。现在,让我们测试一个异步系统。用 JavaScript 编写下面的代码。
注意: 不用担心,我们将在本文后面讨论 setTimeout()
函数。
控制台的结果如下:
既然我们已经了解了同步操作和异步操作之间的区别,那么让我们来创建一个冰淇淋商店。
如何设置我们的项目
对于这个项目,你只需要打开 Codepen.io直接开始编码。或者,你可以用 VS Code 编辑器来做。
打开 JavaScript 部分,然后打开开发人员控制台,我们将编写代码并在控制台中查看结果。
什么是 JavaScript 中的回调函数?
当你将一个函数作为参数嵌套到另一个函数中时,这叫作回调。
下面是一个回调的说明:
一个回调的例子
别担心,我们马上就会看到一些回调的例子。
为什么要使用回调?
在做一个复杂的任务时,我们把它分解成更小的步骤。为了根据时间(可选)和顺序在这些步骤之间建立关系,我们会使用回调。
看看这个例子:
图表包含制作冰淇淋的步骤
这些是制作冰淇淋需要的小步骤。还要注意,在本例中,步骤的顺序和计时是至关重要的,你不能只把水果切了就端上冰淇淋。
同时,如果前一个步骤没有完成,我们就不能进入下一个步骤。
为了更详细地解释这一点,让我们开始做冰淇淋店的生意。
等等...
该店将分为两部分:
储藏室里有所有的配料 - 后台
我们将在厨房里制作冰淇淋 - 前端
让我们存储数据
现在,我们要把配料存储在一个对象中。
你可以像这样在对象中存储成分:
我们的其他食材在这里:
你可以像这样将这些其他成分存储在 JavaScript 对象中:
整个业务取决于客户的 订单。一接到订单,我们就开始生产,然后供应冰淇淋。因此我们将创建两个函数 ->
order
production
这就是它的工作原理:
从客户那里获取订单,取得食材,开始生产,然后上桌。
我们来写一下函数。在这里我们使用箭头函数:
现在,让我们使用回调建立这两个函数之间的关系,如下所示:
让我们做个小测试
我们将使用 console.log()
函数进行测试,以消除关于如何建立这两个函数之间的关系的疑问。
为了运行测试,我们将调用 order
函数。我们将添加第二个函数名为 production
作为它的参数。
下面是控制台中的结果:
休息一下
到目前为止一切都很好,休息一下吧!
清除 console.log 日志
保留这段代码并删除所有的东西,不要删除我们的 stocks 变量。在我们的第一个函数中,传递另一个参数,以便我们可以接收订单,即水果名:
下面是我们的步骤,以及执行每个步骤所需的时间。
图表包含制作冰淇淋的步骤
在这个图表中,你可以看到第一步是下订单,这需要 2 秒。第二步是切水果(2 秒),第三步是加水和冰(1 秒),第四步启动机器(1 秒),第五步是选择容器(2 秒),第六步是选择配料(3 秒),以及第七步,也就是最后一步,端上冰淇淋,这需要 2 秒。
要建立计时,函数 setTimeout()
非常好,因为它也使用一个回调函数作为参数。
setTimeout() 函数的语法
现在,让我们使用这个函数来选择水果:
下面是控制台中的结果:
注意 2 秒后才会显示结果。
如果你想知道我们是如何从 stock 变量中采摘草莓的,下面是代码:
不删除任何代码。现在,我们将使用以下代码开始编写生产函数。我们将使用箭头函数。
结果如下:
我们将在现有的 setTimeout
函数中嵌套另一个 setTimeout
函数来切水果:
结果如下:
如果你还记得,这是我们的步骤:
图表包含制作冰淇淋的步骤
让我们通过在另一个函数中嵌套一个函数来完成我们的冰淇淋生产 - 这也叫作回调,还记得吗?
控制台结果如下:
感到疑惑吗?
这叫作回调地狱,它看起来像这样(还记得上面的代码吗):
回调地狱图解
解决方案是什么?
如何使用 Promise 来避免回调地狱
Promises 的发明是为了解决回调地狱的问题和更好地处理我们的任务。
休息一下
先休息一下!
这就是 promise 的样子
promise 的格式说明
让我们一起来剖析 promise。
promise 周期的图解
如上图所示,一个 promise 有三种状态:
Pending: 这是初始阶段,这里什么也没有发生。你可以这样想,你的客户正在慢慢地给你下订单,但是他们还没有点任何东西。
Resolved: 这意味着你的顾客已经收到了他们的食物并且很高兴
Rejected: 这意味着你的顾客没有收到他们点的单并离开了冰激凌店
让我们将 promise 应用到我们的冰淇淋生产案例研究中。
等等
首先,我们需要了解另外四件事 ->
时间和工作的关系
Promise 链
错误处理
.finally
函数
让我们开始我们的冰淇淋店,一步一步地理解这些概念。
时间和工作的关系
如果你还记得,这就是我们制作冰淇淋的步骤和时间
图表包含制作冰淇淋的步骤
为了实现这一点,让我们在 JavaScript 中创建一个变量:
现在创建一个名叫 order
的函数,然后传两个名叫 time, work
的参数:
现在,我们要向客户发起 promise,"我们将给献上冰淇淋",如下 ->
我们的 promise 有两个部分:
Resolved - 用户拿到了冰激凌
Rejected - 用户没有拿到冰激凌
让我们在 if
语句中使用 setTimeout()
函数在 promise 中添加时间和工作因素。
注意: 在现实生活中,你也可以避免时间因素,这完全取决于你的工作性质。
现在,我们要用新创建的函数开始制作冰淇淋。
2 秒后的结果是:
很棒!
Promise 链
在这个方法中,我们使用 .then
处理后续的程序:
使用 .then 处理函数的 promise 链说明
当我们的 promise 被 resolve 时, .then 处理函数返回一个 promise。
例子如下:
让我说得简单点:这类似于给某人指示,你告诉别人“先做这个,然后做那个,然后做其他的事情,然后…”,然后……,然后……”等。
他的首要任务是我们原始 promise
一旦完成了一小部分工作,剩下的任务就返回了新的 promise
让我们在项目中实现这一点。在代码的底部编写以下代码行。
注意: 不要忘记在 .then
函数中写 return
。否则,它将不能正常工作。如果你很好奇,试着在我们完成这些步骤后去掉返回值:
结果如下:
使用相同的系统,让我们完成我们的项目:
结果如下:
错误处理
当出现错误时,我们需要一种处理错误的方法。但首先,我们需要了解 promise 周期。
promise 周期说明
为了捕获错误,让我们将变量改为 false。
也就是说我们的店关门了,我们不再卖冰淇淋给顾客了。
为了处理这种情况我们使用 .catch
函数,类似 .then
,它也返回一个 promise,但只有当我们最初的 promise 被 reject 时才会执行。
这里有一个小提示:
.then
在 promise resolved 时候被执行.catch
在 promise rejected 时候被执行
到代码最底部,编写以下代码:
记住在.then
和 .catch
之间不能有任何东西。
结果如下:
关于这段代码,有两点需要注意:
第一个信息是从
reject()
部分来的第二个信息是从
catch()
部分来的
如何使用 .finally() 函数
有一个叫作 “finally” 的函数,不管我们的 promise 是被 resolve 了还是被 reject 了,它都会被执行。
例如: 不管我们是没有顾客还是有 100 个顾客,我们的店都会在一天结束的时候关门。
如果您想对此进行测试,请在最下面编写以下代码:
结果如下:
请大家欢迎 Async/Await~
Async/Await 如何在 JavaScript 中运行
这应该是编写 promise 的更好方式,它可以帮助我们保持代码的简单和干净。
你所要做的就是在任何常规函数之前写 async
关键字,它就变成了一个 promise。
先休息一下
让我们来看一看:
JavaScript 中 Promises vs Async/Await
在 async/await 之前,为了写一个 promise,我们这样写:
现在使用 async/await,我们可以这么写:
等等...
你必须理解->
如何使用
try
和catch
关键字如何使用
await
关键字
如何使用 Try 和 Catch 关键字
我们使用 try
关键字来运行代码,同时使用 catch
来捕获错误。这和我们看 promise 时看到的概念是一样的。
让我们来比较一下。我们来看一个小 demo,然后开始编码。
JS 中的 Promise -> resolve 和 reject
我们在 resolve 中这样使用 resolve 和 reject:
JS 中的 Async/Await -> try, catch
当我们使用 async/await 时,可以这么写:
不要慌,我们接下来将讨论 await
关键字。
现在希望你理解了 promise 和 async/await 之间的区别了。
如何使用 JavaScript 的 Await 关键字
关键字 await
使 JavaScript 等待,直到一个 promise reslove 时才会返回它的结果。
如何在 JavaScript 中使用 await 关键字
我们回冰淇淋店去吧。我们不知道顾客更喜欢哪种配料,巧克力还是花生,所以我们需要停止机器,然后去问顾客他们想在冰淇淋上加什么。
注意这里只有我们的厨房被停止了,但是我们在厨房外的员工仍然会做这样的事情:
洗餐具
清洁桌子
点单,等等
一个 Await 关键字代码示例
让我们创建一个小 promise 来询问要使用那种配料,这个过程需要 3 秒。
现在,让我们首先使用 async 关键字来创建 kitchen 函数。
让我们在 kitchen()
调用下面添加其他任务。
结果如下:
我们走出厨房问我们的顾客,“你想要哪种配料?”,与此同时,还有其他事情要做。
一旦他们选好了配料,我们就进入厨房,完成任务。
注意
当使用 Async/Await 时,你也可以使用 promise 的核心部分 .then
、.catch
和 .finally
函数。
我们再开一家冰淇淋店吧
我们要创建两个函数 ->
kitchen
: 制作冰激凌time
: 分配好每一项小任务所需要的时间
让我们开始吧!先创建时间函数:
现在,让我们创建我们的厨房:
让我们来做个小说明,看看我们的厨房功能是否正常:
当商店开门时,结果是这样的:
当商店关门时,结果是这样的:
到目前为止一切顺利。
让我们完成我们的项目。
下面是我们的任务列表:
图表包含制作冰淇淋的步骤
首先,开张:
现在在 kitchen()
函数中编写步骤:
结果如下:
总结
恭喜你读完了本文!在本文中,你可以了解到:
同步和异步系统之间的区别
异步 JavaScript 使用 3 种机制(callbacks、promises 和 Async/Await)
这是你阅读到最后的奖励。❤️
原文
作者:Joy Shaheb
成品: JavaScript Async/Await 教程——通过制作冰淇淋来学习 JavaScript 异步编程
译者:Miever
版权声明: 本文为 InfoQ 作者【Miever】的原创文章。
原文链接:【http://xie.infoq.cn/article/3d3963095f0cdf938004f2cb2】。未经作者许可,禁止转载。
评论