问题:与常规函数的return语句相比,在引擎运行时将函数声明为async
并最终声明为await
是否有计算开销(如果有,在多大程度上)?
async function foo() {
var x = await bar(); // <--- bar() is non-blocking so await to get the return value
return x; // the return value is wrapped in a Promise because of async
}
字符串
与
function foo() {
var x = bar(); // <--- bar() is blocking inside its body so we get the return value
return new Promise(resolve => { resolve(x); }); // return a Promise manually
}
型
上下文:
由于JavaScript(即Nodejs)采取的异步方向,为什么他们不认为每个函数默认都是异步的(根据async
关键字)?
这样,人们可以决定将任何函数调用视为Promise
并玩异步游戏,或者只是await
。
我认为函数体中的await
-ing会产生堆叠本地函数作用域的开销,而当函数返回时,正常的事件循环会继续进行,并且不必将内部函数作用域推入堆栈?
这归结为一个额外的问题:在一个复杂的类的虚拟系统中,(在某个深度)需要一个同步IO操作(见注),这将是理想的await
'ed。只有当该方法被标记为async
时才有可能。这反过来又要求调用函数是async
,以便能够再次执行await
。因此,在需要的时候,所有东西都标记为async
和await
..
注意:请不要争论不做任何同步操作的必要性,因为这不是重点。
注2:这个问题不是关于什么是await
或async
,也不是关于它何时执行的,而是关于性能和语言的内部结构(即使存在多个实现,概念也可能存在固有的语义开销)。
3条答案
按热度按时间lhcgjxsq1#
与同步函数相比,异步函数具有固有的开销。当然可以将所有内容都设置为异步函数,但您可能会很快遇到性能问题。
同步vs异步
函数返回一个值。
async
函数创建一个Promise对象,并从函数返回。Promise对象的设置是为了维护异步任务的状态,并处理错误或后续的链式调用。Promise将在事件循环的下一个tick之后被解析或拒绝。(这有点简短,如果你想了解细节,请使用read the the spec)与简单的函数调用和返回值相比,这具有内存和处理开销。量化开销是有点无用的,因为大多数Node.js函数都是Node.js函数,因为它们必须等待外部Node.js线程来完成一些工作,通常执行缓慢的IO。与操作的总时间相比,设置Promise的开销非常小,特别是如果替代方案是阻塞主JS线程。
另一方面,同步代码在主JS线程中立即运行。交叉区域是调度同步代码,用于定时或将主JS线程的使用“节流”到下一个tick,以便GC和其他JavaScript任务有机会运行。
如果你在一个紧循环中一个字符接一个字符地解析一个字符串,你可能不想创建一个promise并等待它在每次迭代中解析,因为完成这个过程所需的内存和时间会迅速增加。
另一方面,如果你的应用程序只做query a database,并将结果转储到koa http响应中,那么你可能会在一个python promise中做大多数事情(尽管下面仍然有很多同步函数来实现这一点)。
愚蠢的例子
一个人为示例的基准测试,同步返回和解决同一同步操作的各种方法之间的差异。
字符串
运行
型
如果你想更详细地比较各种promise和callback实现的性能/开销,也可以检查bluebirds benchmarks。
型
cedebl8k2#
有一些操作是不需要等待的,例如,如果你想执行几个XHR,同时加载几个文件,自动等待会使加载过程线性化,这是不好的
twh00eeo3#
Promises/await和Promises的优点在于你可以混合使用。对于多个XHR请求,你可以简单地返回Promise.all():
字符串