小心异步/等待

2020-07-31 00:04:31

712 Brandon Smith异步函数getPeople(){const Members=等待获取(";/Members";);const非成员=等待获取(";/Non-Members";);返回成员。Concat(非成员);}。

花点时间看一下。类似这样的代码可能存在于更多的JavaScript代码库中。有时,它就在更了解情况的人的眼皮底下,包括我自己。事实上,我在一个案例中犯了这个错误,这就是促使我最初写这篇文章的原因。

你现在看到了吗?实际上,甚至编写这个版本都很棘手,因为如果没有异步/等待,就很难犯这个错误。

我们采用了两个独立的异步任务,并将它们放入一个序列中。此功能所需的时间是所需时间的两倍。

异步函数getPeople(){const Members=FETCH(";/Members";);Const Non Members=Fetch(";/Non-Members";);Const Both=等待承诺。All([Members,NonMembers]);返回两者[0]。Concat(两者均为[1]);}。

函数getPeople(){const Members=Fetch(";/Members";);const Non Members=Fetch(";/Non-Members";);Return Promise。全部([成员,非成员])。则(Both=>;Both[0]。CONCAT(两者[1]));}。

请注意,当写成简单的承诺时,糟糕的版本要复杂得多。Promises API鼓励并行性,当您需要按顺序放置东西时,它会变得笨拙。异步/等待在很大程度上是作为一种解决方案出现的,用于当您确实需要按顺序发生事情时,比如当您需要将一个请求的输出作为参数提供给下一个请求时。而且可以说,这至少让这两个案件都变得更干净了。但重要的是,它颠倒了它们,使顺序流比平行流更容易。

即使您理解语法最终要转换成的承诺代码,也很容易落入这种陷阱。如果你还不了解承诺以及异步/等待到底在做什么,那就更不用说了。

我不会说异步/等待是不好的(或者,也许被认为是有害的)。特别是在那些没有合理API(如承诺)的语言中,或者在闭包方面有其他限制使它们不那么容易使用的语言中,异步/等待可以使代码总体上更具可读性。

但它们确实伴随着一个相当大的陷阱。该语法的优点和缺点都在于,它允许我们接受异步的事物,并假装它们再次是连续的。我们的大脑更容易对顺序过程进行推理。

但我认为,使用Async/AWait编写内容的最简单、最清晰的方法往往是错误的,这是一种遗憾。并以一种可能永远不会被注意到的微妙方式出错,因为它只影响性能,而不影响正确性。

我是语言和图书馆的忠实拥护者,因为语言和图书馆让做通常正确的事情变得容易,做通常错误的事情变得困难。这就是说,对于异步/等待如何能够以不同的方式实现,我没有一个建议。我只是后悔事情变成这样。

但至少,我认为随着越来越多的语言采用这种语法,人们意识到它很容易被误用,这一点变得越来越重要。

如果您不确定代码是如何运行的,请查看瀑布图,看看是否有机会使应用程序更快。

您还可以使用这个经验法则:如果等待的函数调用没有使用另一个等待的函数调用的结果(或从结果派生的结果),则应该使用Promise.all()使它们同时发生。