在 React 中使用 Async/Await 处理嵌套 Promise
介绍
异步代码总是会带来认知开销。人类的思维可能习惯于同步思考,因此试图理解异步代码似乎是一件令人望而生畏的事情。多年来,已经出现了许多试图缓解这种复杂性的构造。长期以来,在 JavaScript 代码中模拟异步的唯一方法是通过回调。回调的问题在于它们会在您的应用程序中留下一串“意大利面条式”代码——您可能熟悉“回调地狱”这个术语。
现代 JavaScript 引入了一种建模异步代码的新方法:Promises。Promises 使 JavaScript 和 React 开发人员能够编写无需回调的异步代码 - 但是,在旧样式中嵌套 Promises 仍然很容易,这会导致代码难以阅读。
现代 JavaScript 中引入的新 async/await 关键字旨在通过在承诺之上提供“语法糖”来解决此问题。在本指南中,您将学习如何利用 async/await 来简化 React 应用中的嵌套承诺。您将看到如何不仅可以将编写的异步代码量减少一半,还可以消除所涉及的大部分心理复杂性。您将看到 async/await 语法如何让您以同步方式推理异步代码。
让我们开始吧。
问题概述:嵌套 Promises
以下列方式编写的代码并不罕见。下面,您可以看到一些典型的异步代码,它们使用嵌套承诺来发出连续的 HTTP 请求以获取“炸鱼和薯条”。大多数情况下,您会看到这样编写的代码的原因是,这通常是您编写异步代码的第一直觉。
// my-component.jsx
// We have to get chips after we get fish...
getFishAndChips = () => {
fetch(this.fishApiUrl) // Request fish
.then(fishRes => {
fishRes.json().then(fish => {
this.fish = fish;
const fishIds = fish.map(fish => fish.id);
fetch( // Request chips using fish ids
this.chipsApiUrl,
{
method: 'POST',
body: JSON.stringify({ fishIds })
}
)
.then(chipsRes => {
chipsRes.json().then(chips => {
this.chips = chips;
})
})
})
})
}
上面的代码嵌套了两个fetch调用,以确保您在请求鱼之后请求薯条。这是因为,为了请求薯条,您需要使用 POST 请求发送鱼 ID 数组。这可以行得通,但是这里有一个巨大的可读性问题。编写上述代码就像是用回调地狱换取……承诺地狱!谁想这样做!?可以大大减少此功能所需的代码量。让我们来看看承诺链!
临时解决方案:Promise Chaining
消除这些fetch调用嵌套的第一种方法是使用所谓的 Promise 链。只需在Promise.then调用中返回另一个 Promise 即可实现 Promise 链。以下示例显示了如何执行此操作:
// We have to get chips after we get fish...
getFishAndChips = () => {
fetch(this.fishApiUrl) // Request fish
.then(response => response.json())
.then(fish => {
this.fish = fish;
const fishIds = fish.map(fish => fish.id);
return fetch( // Request chips using fish ids
this.chipsApiUrl,
{
method: 'POST',
body: JSON.stringify({ fishIds })
}
);
})
.then(response => response.json())
.then(chips => {
this.chips = chips;
});
}
这太棒了!代码更易于维护、简洁且易读。但我们可以做得更好!借助 JavaScript 中引入的新 async/await 语法,我们可以完全消除对Promise.then的多次调用!您将在下一节中看到如何实现这一点。
最佳解决方案:Async/Await
async/await 关键字是一种在计算机程序中建模异步控制流的绝妙机制。在 JavaScript 中,这些关键字是 Promises 之上的语法糖 — 它们抽象出对Promise.then的调用。在下面的代码中,我们重构getFishAndChips函数以使用 async/await。
// We have to get chips after we get fish...
getFishAndChips = async () => {
const fish = await fetch(this.fishApiUrl).then(response => response.json());
const fishIds = fish.map(fish => fish.id),
chipReqOpts = { method: 'POST', body: JSON.stringify({ fishIds }) };
const chips = await fetch(this.chipsApiUrl, chipReqOpts).then(response => response.json());
}
哇!将第一部分的第一个代码片段与此代码进行比较。差别太大了!我们大大压缩了所使用的代码,同时实现了相同的效果。此代码更易于阅读和维护。您可以轻松看到,通过能够以同步方式推理代码,可以减少多少思维复杂性 - 无需嵌套!只需使用 async 关键字标记您的异步函数即可。这使您可以使用await关键字为您解决承诺!控制流的 async/await 机制是一种非常强大的方式,可以推理应用程序内的任何异步内容。
结论
在应用中编写链式异步操作序列可能很困难。嵌套承诺是实现此操作的一个不幸的副产品。但值得庆幸的是,正如您在本指南中看到的那样,通过承诺链或 async/await 语法可以轻松避免和/或重构嵌套承诺。在这两种解决方案中,最易读的代码是使用 async/await 语法编写的,因此请努力在您自己的应用中使用它!
现在,您可以自信地在 React 组件中编写现代且可读的异步代码!有关更多信息,请查看async/await 语法的文档。
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~