异步回调地狱_如何逃避异步/等待地狱
异步回调地狱
async/await freed us from callback hell, but people have started abusing it — leading to the birth of async/await hell.
async / await使我们从回调地狱中解脱出来,但是人们已经开始滥用它-导致async / await地狱的诞生。
In this article, I will try to explain what async/await hell is, and I’ll also share some tips to escape it.
在本文中,我将尝试解释什么是异步/等待地狱,并且还将分享一些技巧以逃避它。
什么是异步/等待地狱 (What is async/await hell)
While working with Asynchronous JavaScript, people often write multiple statements one after the other and slap an await before a function call. This causes performance issues, as many times one statement doesn’t depend on the previous one — but you still have to wait for the previous one to complete.
在使用异步JavaScript时,人们经常一个接一个地编写多个语句,并在函数调用之前先等待 。 这会导致性能问题,因为很多时候一个语句不依赖于前一个语句,但是您仍然必须等待上一个语句完成。
一个异步/等待地狱的例子 (An example of async/await hell)
Consider if you wrote a script to order a pizza and a drink. The script might look like this:
考虑一下您是否编写了脚本来订购比萨饼和饮料。 该脚本可能如下所示:
On the surface it looks correct, and it does work. But this is not a good implementation, because it leaves concurrency out of the picture. Let’s understand what its doing so that we can nail down the issue.
从表面上看,它是正确的,并且确实起作用。 但这不是一个很好的实现,因为它使并发不存在。 让我们了解一下它在做什么,以便我们可以找出问题所在。
说明 (Explanation)
We have wrapped our code in an async IIFE. The following occurs in this exact order:
我们已经将代码包装在异步IIFE中 。 以这种确切的顺序发生以下情况:
- Get the list of pizzas.获取比萨饼列表。
- Get the list of drinks.获取饮料清单。
- Choose one pizza from the list.从列表中选择一个披萨。
- Choose one drink from the list.从列表中选择一种饮料。
- Add the chosen pizza to the cart.将选定的比萨饼添加到购物车。
- Add the chosen drink to the cart.将所选的饮料添加到购物车。
- Order the items in the cart.订购购物车中的物品。
那怎么了? (So what’s wrong ?)
As I stressed earlier, all these statements execute one by one. There is no concurrency here. Think carefully: why are we waiting to get the list of pizzas before trying to get the list of drinks? We should just try to get both the lists together. However when we need to choose a pizza, we do need to have the list of pizzas beforehand. The same goes for the drinks.
正如我之前强调的那样,所有这些语句都一个接一个地执行。 这里没有并发。 仔细想想:为什么我们要先获得比萨饼清单,然后再尝试获取饮料清单? 我们应该尝试将两个列表放在一起。 但是,当我们需要选择披萨时,我们确实需要事先获得披萨列表。 饮料也一样。
So we can conclude that the pizza related work and drink related work can happen in parallel, but the individual steps involved in pizza related work need to happen sequentially (one by one).
因此,我们可以得出结论,与比萨饼相关的工作和与饮料相关的工作可以并行进行,但是与比萨饼相关的工作中涉及的各个步骤需要依次进行(一个接一个)。
错误执行的另一个例子 (Another example of bad implementation)
This JavaScript snippet will get the items in the cart and place a request to order them.
这个JavaScript程式码片段将把商品放入购物车中,并提出订购要求。
async function orderItems() {const items = await getCartItems() // async callconst noOfItems = items.lengthfor(var i = 0; i < noOfItems; i++) {await sendRequest(items[i]) // async call}
}
In this case, the for loop has to wait for the sendRequest()
function to complete before continuing the next iteration. However, we don’t actually need to wait. We want to send all the requests as quickly as possible and then we can wait for all of them to complete.
在这种情况下,for循环必须等待sendRequest()
函数完成才能继续下一次迭代。 但是,我们实际上不需要等待。 我们希望尽快发送所有请求,然后我们可以等待所有请求完成。
I hope that now you are getting closer to understanding what is async/await hell and how severely it affects the performance of your program. Now I want to ask you a question.
我希望现在您可以进一步了解什么是异步/等待地狱,以及它如何严重影响程序的性能。 现在我想问你一个问题。
如果我们忘记了await关键字怎么办? (What if we forget the await keyword ?)
If you forget to use await while calling an async function, the function starts executing. This means that await is not required for executing the function. The async function will return a promise, which you can use later.
如果您在调用异步函数时忘记使用await ,该函数将开始执行。 这意味着执行功能不需要等待。 异步函数将返回一个Promise,您可以稍后使用。
(async () => {const value = doSomeAsyncTask()console.log(value) // an unresolved promise
})()
Another consequence is that the compiler won’t know that you want to wait for the function to execute completely. Thus the compiler will exit the program without finishing the async task. So we do need the await keyword.
另一个结果是,编译器不会知道您要等待函数完全执行。 因此,编译器将在不完成异步任务的情况下退出程序。 所以我们确实需要await关键字。
(async () => {const promise = doSomeAsyncTask()const value = await promiseconsole.log(value) // the actual value
})()
One interesting property of promises is that you can get a promise in one line and wait for it to resolve in another. This is the key to escaping async/await hell.
Promise的一个有趣特性是,您可以在一行中获得一个Promise,然后在另一行中等待它解决。 这是逃避异步/等待地狱的关键。
As you can see, doSomeAsyncTask()
is returning a promise. At this point doSomeAsyncTask()
has started its execution. To get the resolved value of the promise, we use the await keyword and that will tell JavaScript to not execute the next line immediately, but instead wait for the promise to resolve and then execute the next line.
如您所见, doSomeAsyncTask()
返回了一个doSomeAsyncTask()
。 此时, doSomeAsyncTask()
已开始执行。 为了获得promise的解析值,我们使用await关键字,它将告诉JavaScript不要立即执行下一行,而是等待promise解析后再执行下一行。
如何摆脱异步/等待地狱? (How to get out of async/await hell ?)
You should follow these steps to escape async/await hell.
您应该按照以下步骤逃避异步/等待地狱。
查找依赖于其他语句执行的语句 (Find statements which depend on the execution of other statements)
In our first example, we were selecting a pizza and a drink. We concluded that, before choosing a pizza, we need to have the list of pizzas. And before adding the pizza to the cart, we’d need to choose a pizza. So we can say that these three steps depend on each other. We cannot do one thing until we have finished the previous thing.
在第一个示例中,我们选择披萨和饮料。 我们得出的结论是,在选择披萨之前,我们需要获得披萨清单。 在将比萨饼添加到购物车之前,我们需要选择一个比萨饼。 因此,我们可以说这三个步骤相互依赖。 在完成前一件事之前,我们无法做一件事。
But if we look at it more broadly, we find that selecting a pizza doesn’t depend on selecting a drink, so we can select them in parallel. That is one thing that machines can do better than we can.
但是,如果从更广泛的角度来看,我们发现选择披萨并不取决于选择饮料,因此我们可以并行选择它们。 这是机器可以做得比我们更好的一件事。
Thus we have discovered some statements which depend on the execution of other statements and some which do not.
因此,我们发现了一些依赖于其他语句执行的语句,而另一些则不依赖于其他语句的执行。
异步函数中与组相关的语句 (Group-dependent statements in async functions)
As we saw, selecting pizza involves dependent statements like getting the list of pizzas, choosing one, and then adding the chosen pizza to the cart. We should group these statements in an async function. This way we get two async functions, selectPizza()
and selectDrink()
.
如我们所见,选择比萨饼涉及一些相关语句,例如获取比萨饼列表,选择一个比萨饼,然后将所选的比萨饼添加到购物车中。 我们应该将这些语句分组到一个异步函数中。 这样,我们得到两个异步函数, selectPizza()
和selectDrink()
。
同时执行这些异步功能 (Execute these async functions concurrently)
We then take advantage of the event loop to run these async non blocking functions concurrently. Two common patterns of doing this is returning promises early and the Promise.all method.
然后,我们利用事件循环来同时运行这些异步非阻塞函数。 两种常见的执行方法是尽早返回 Promise和Promise.all方法 。
让我们修复示例 (Let’s fix the examples)
Following the three steps, let’s apply them on our examples.
按照这三个步骤,让我们将其应用于示例。
async function selectPizza() {const pizzaData = await getPizzaData() // async callconst chosenPizza = choosePizza() // sync callawait addPizzaToCart(chosenPizza) // async call
}async function selectDrink() {const drinkData = await getDrinkData() // async callconst chosenDrink = chooseDrink() // sync callawait addDrinkToCart(chosenDrink) // async call
}(async () => {const pizzaPromise = selectPizza()const drinkPromise = selectDrink()await pizzaPromiseawait drinkPromiseorderItems() // async call
})()// Although I prefer it this way Promise.all([selectPizza(), selectDrink()]).then(orderItems) // async call
Now we have grouped the statements into two functions. Inside the function, each statement depends on the execution of the previous one. Then we concurrently execute both the functions selectPizza()
and selectDrink()
.
现在,我们将语句分为两个功能。 在函数内部,每条语句取决于前一条的执行。 然后,我们同时执行selectPizza()
和selectDrink()
函数。
In the second example, we need to deal with an unknown number of promises. Dealing with this situation is super easy: we just create an array and push the promises in it. Then using Promise.all()
we concurrently wait for all the promises to resolve.
在第二个示例中,我们需要处理数量未知的promise。 处理这种情况非常容易:我们只需创建一个数组,然后将诺言推入其中即可。 然后,使用Promise.all()
并发地等待所有诺言得以解决。
async function orderItems() {const items = await getCartItems() // async callconst noOfItems = items.lengthconst promises = []for(var i = 0; i < noOfItems; i++) {const orderPromise = sendRequest(items[i]) // async callpromises.push(orderPromise) // sync call}await Promise.all(promises) // async call
}// Although I prefer it this way async function orderItems() {const items = await getCartItems() // async callconst promises = items.map((item) => sendRequest(item))await Promise.all(promises) // async call
}
I hope this article helped you see beyond the basics of async/await, and also helped you improve the performance of your application.
我希望本文可以帮助您了解异步/等待的基础知识,也可以帮助您提高应用程序的性能。
If you liked the article, please clap your heart out. Tip — You can clap 50 times!
如果您喜欢这篇文章,请鼓掌。 提示—您可以拍手50次!
Please also share on Fb and Twitter. If you’d like to get updates, follow me on Twitter and Medium or subscribe to my newsletter! If anything is not clear or you want to point out something, please comment down below.
也请在Fb和Twitter上分享。 如果您想获取更新,请在Twitter和Medium上关注我,或订阅我的新闻 ! 如果有任何不清楚的地方,或者您想指出点什么,请在下方留言。
翻译自: https://www.freecodecamp.org/news/avoiding-the-async-await-hell-c77a0fb71c4c/
异步回调地狱
相关文章:

2015年编程之美(资格赛) ---2月29日
时间限制:2000ms单点时限:1000ms内存限制:256MB描述 给定两个日期,计算这两个日期之间有多少个2月29日(包括起始日期)。 只有闰年有2月29日,满足以下一个条件的年份为闰年: 1. 年份能被4整除但不能被100整除 2. 年份能…

2016多校赛2 A 数学推公式 E 极角排序,组合数(待补) L dp+bitset优化
2016 Multi-University Training Contest 2 A - Acperience 题意:给出w[],求S((w[i]-aB[i])^2)的最小值(B[i]为1或-1)。 tags:一看到就搞了个三分上去,估计是精度问题,一直挖,23333。。 就是把这个公式推下…

php No 'Access-Control-Allow-Origin' header is present on the requested resource.'Ajax跨域访问解决方法
微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 在PHP请求头加上 header("Access-Control-Allow-Origin: *");

二进制搜索算法_使用安全摄像机镜头解释二进制搜索算法
二进制搜索算法by Julia GeistJulia盖斯特(Julia Geist) 使用安全摄像机镜头解释二进制搜索算法 (Binary Search Algorithms explained using security camera footage) Binary search, also known as half-interval search or logarithmic search, is a search algorithm tha…

Codeforces 460E Roland and Rose(暴力)
题目链接:Codeforces 460E Roland and Rose 题目大意:在以原点为圆心,半径为R的局域内选择N个整数点,使得N个点中两两距离的平方和最大。 解题思路:R最大为30。那么事实上距离圆心距离最大的整数点只是12个最多&#x…

HTML POST提交参数给PHP并返回json,上传execl文件
微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文: 需求:AJAX post带参数请求接口,PHP接收后存入数据库;然后返回json数据循环渲染到HTML <!DOCTYPE html> <html lang"zh">&l…

在Ubuntu 12.04 桌面上设置启动器(快捷方式)
在Ubuntu 12.04 桌面上设置启动器(快捷方式)过程讲解: 如下图所示,Eclipse 和 SQLDeveloper 都可以直接双击打开,这些应用程序的启动器都在 /usr/share/applications文件夹下面,进入后将其复制到桌面即可。…

rxswift中hud_如何在RxSwift中运行测试
rxswift中hudby Navdeep Singh通过Navdeep Singh 如何在RxSwift中运行测试 (How to run tests in RxSwift) RxTest and RxBlocking are part of the RxSwift repository. They are made available via separate pods, however, and so require separate imports.RxTest和RxBlo…

安装完DevExpress14.2.5,如何破解它呢?
DevExpress是一个界面控件套件,提供了一系列的界面控件套件的DotNet界面控件。DevExpress开发的控件有很强的实力,不仅功能丰富,应用简单,而且界面华丽,更可方便订制,方便开发人员开发。 下面介绍DevExpres…

Extjs Ext.TreePanel
TreePanel 简单实例。 <link rel"stylesheet" href"Js/ext-4.2/resources/css/ext-all-neptune.css"/><script src"Js/jQuery/jquery-1.8.2.min.js" type"text/javascript"></script><script src"Js/ext-…

php模糊搜索功能
微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文: 前端 前端post请求并发送str参数>搜索的内容; PHP <?phpheader("Content-Type:text/html;charsetutf8"); header("Access-Control-Allow-Origin…

react 快速上手开发_React中测试驱动开发的快速指南
react 快速上手开发by Michał Baranowski通过MichałBaranowski React中测试驱动开发的快速指南 (A quick guide to test-driven development in React) Following the principles of Test-Driven Development (TDD) when writing a front-end React app might seem more dif…

iOS 相册和网络图片的存取
iOS 相册和网络图片的存取 保存 UIImage 到相册 UIKit UIKit 中一个古老的方法,Objective-C 的形式 void UIImageWriteToSavedPhotosAlbum(UIImage *image, id completionTarget, SEL completionSelector, void *contextInfo); 保存完成后,会调用 comple…

微信小程序实时聊天之WebSocket
微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文: 1.所有监听事件先在onload监听。 // pages/index/to_news/to_news.js var app getApp(); var socketOpen false; var SocketTask false; var url ws://192.168.0.120:7011; Page…

webform repeater
repeater:由模板构成,解析后模板就不存在了 需要指定数据源进行数据绑定 List<Fruit> list new FruitDA().Select(); // 数据查询 (随便查寻的) Repeater1.DataSource list; // 赋值 Repeater1…

远程协助软件开发_这是我从事远程软件开发人员工作的主要技巧
远程协助软件开发by Colin Morgan通过科林摩根(Colin Morgan) 这是我从事远程软件开发人员工作的主要技巧 (Here are the top tips I’ve used to land a remote software developer job) Applying for a remote software developer job means you are voluntarily choosing t…

简谈-Python一些常用的爬虫技巧
第一种:基本的网页抓取 get方法 import urllib2url "链接response urllib2.urlopen(url)print response.read() post方法 import urllibimport urllib2url "链接form {name:abc,password:1234}form_data urllib.urlencode(form)request urllib2.Req…

微信小程序画布圆形进度条demo
微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文: wxml <!--pages/test/test.wxml--> <canvas style"width: 300px; height: 200px;" canvas-id"canvasid"></canvas>js // pages/test/test.js …

smarty 模板引擎
http://blog.csdn.net/zuiaituantuan/article/details/5951242 http://wenku.baidu.com/link?url-UHlSnTXOOAjFG1KjX6T9sEG6V4hNAMfRDpMuRRnc_FKbFAxiE5Ntk4lzxSm-7Z531uWdfvgYx81sdC61SgTZm7q8FdUt3gSs7ZlC0JR1SW转载于:https://www.cnblogs.com/hxjbc/p/4441879.html

flask url构建_如何为生产构建构建Flask-RESTPlus Web服务
flask url构建by Greg Obinna由格雷格奥比纳(Greg Obinna) 如何为生产构建构建Flask-RESTPlus Web服务 (How to structure a Flask-RESTPlus web service for production builds) In this guide I’ll show you a step by step approach for structuring a Flask RESTPlus web…

【2017-4-26】Winform 公共控件 菜单和工具栏
作废 等待重写 名称 功能取值赋值备注Button按钮多用来触发点击事件 CheckBox多选按钮 CheckedListBox多选按钮组 ComboBox下拉列表 DateTimePicker指定的格式选择时间日期 Lable说明性文字控件 LinkLable超链接类型文件控件 ListBox用户选择项 ListVie…

微信小程序限制当前位置和目的地的距离
微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文: 1。获取当前位置经纬度 onLoad: function (options) {var that this;campaign_id campaign_idwx.getLocation({type: wgs84,success: function (res) {console.log(res)lat1 res.l…

命令行的全文搜索工具--ack
想必大家在命令行环境下工作时候,一定有想要查找当前目录下的源代码文件中的某些字符的需求,这时候如果使用传统方案,你可能需要输入一长串的命令,比如这样: 1. grep -R string dir/ 或者 grep -r -e string direct…

ecmascript_TC39及其对ECMAScript的贡献
ecmascriptby Parth Shandilya通过Parth Shandilya TC39及其对ECMAScript的贡献 (TC39 and its contributions to ECMAScript) Many people get confused about what is JavaScript and what is ECMAScript. Sometimes it’s hard to tell how they are connected with each o…

Winio驱动在64位windows下无法使用的解决方法
C#在使用WinIo的驱动开发类似按键精灵一类工具的时候,需要对相关的驱动进行注册才能正常启动,找了下资料,资料来自: http://jingyan.baidu.com/article/642c9d34e55bd9644b46f74e.html 我在这里进行转载: Winio驱动在6…

js获取前后几天或者前后几个月的日期
微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 ; 正文: demo: 1.获取前后几天的日期 // pages/test/test.jsPage({onLoad: function (options) {var day -7;console.log(GetDay(day))}, }) function GetDay(day) {var tim…

nodejs安装、配置及开发工具
学了node一段时间,但是node的安装还是有一点迷糊。今天新换电脑,所以,需要从头开始,发现node的安装还是不顺畅,这篇随笔是之前学的时候写,但是今天再打开看的时候,发现其他好像没有什么内容&…

拨测工具_您可以拨多少钱? 快速简单地介绍有用的工具。
拨测工具by Miguel Bustamante通过Miguel Bustamante 您可以卷曲多少? 快速简单地介绍有用的工具。 (How much can you cURL? A quick and easy intro to a useful tool.) On a good day I can flex a 20 lb weight…twice. Probably. But that’s not the type o…

leetcode第一刷_Recover Binary Search Tree
这是一道好题,思路尽管有,可是提交之后总是有数据过不了,又依照数据改改改。最后代码都没法看了。收到的教训是假设必须为自己的代码加上非常多非常多特殊的限定。来过一些特殊的数据的话。说明代码本身有非常大的漏洞。 这道题,我…

Java中的文件路径
通常情况下,在Java项目中,我们使用的路径都是在拿到类加载路径后,根据相对位置,使用 FilePathTest.class.getResourceAsStream(relativePath);拿到文件。今天小生不使用classPath,而是直接去使用相对路径来…