Sim*_*mon 10 javascript asynchronous node.js
问题:与常规函数的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
}
Run Code Online (Sandbox Code Playgroud)
与
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
}
Run Code Online (Sandbox Code Playgroud)
背景:
由于Javascript(和Nodejs)采用异步方向,为什么他们不async
默认每个函数都是异步的(按照关键字)?
通过这种方式,人们可以决定将任何函数调用视为一个Promise
并播放异步游戏,或者仅仅await
是必要的.
我想 - await
在一个函数体内创建堆叠本地函数范围的开销,而正常的事件循环在函数返回时继续,而不必将内部函数范围推送到堆栈?
这归结为一个额外的问题:在一个复杂的类层次中(深处某个地方)需要一个理想情况下需要的同步IO操作(参见注释)await
.只有将该方法标记为,才有可能async
.这又要求调用功能async
能够await
再次使用它等等.因此,所有标记async
和await
需要时...如何处理这样的情况?
注意:请不要争论不进行任何同步操作的必要性,因为这不是重点.
注2:这个问题不是关于什么是什么await
或什么async
时候执行.这个问题是关于性能和语言的内部结构(尽管存在多个实现,但概念可能存在固有的语义开销).
与同步功能相比,异步功能具有固有的开销。当然可以使所有内容异步,但是您很可能会很快遇到性能问题。
函数返回一个值。
一个async
函数创建一个承诺对象从函数返回。设置Promise对象以维护异步任务的状态并处理错误或后续的链接调用。事件循环的下一个滴答声之后,承诺将被解决或拒绝。(这有点简短,如果需要详细信息,请阅读规范。)与简单的函数调用和返回值相比,这既有内存,也有处理开销。
但是,对开销进行量化是没有用的,因为大多数异步功能都是异步的,这是因为它们必须等待外部Node.js线程来完成某些工作,通常会做慢IO。与操作的总时间相比,设置Promise的开销非常小,尤其是如果替代方法是阻塞主JS线程的话。
另一方面,同步代码立即在JS主线程中运行。跨接区域正在调度同步代码,以用于定时或“限制”主JS线程到下一个刻度,以便GC和其他异步任务有运行的机会。
如果您处于一个用char解析字符串char的紧密循环中,则可能不想创建一个promise并等待它在每次迭代中解析,因为完成该过程的内存和时间要求将迅速爆炸。
另一方面,如果您的应用程序要做的只是查询数据库并将结果转储到koa http响应中,则您可能会在异步承诺中做大多数事情(尽管在下面仍然有很多同步功能使之发生)。
一个人为例子的基准,同步返回和解决同一同步操作的各种异步方法之间的区别。
const Benchmark = require('benchmark')
const Bluebird = require('bluebird')
let a = 3
const asyncFn = async function asyncFn(){
a = 3
return a+2
}
const cb = function(cb){
cb(null, true)
}
let suite = new Benchmark.Suite()
suite
.add('fn', function() {
a = 3
return a+2
})
.add('cb', {
defer: true,
fn: function(deferred) {
process.nextTick(()=> deferred.resolve(a+2))
}
})
.add('async', {
defer: true,
fn: async function(deferred) {
let res = await asyncFn()
deferred.resolve(res)
}
})
.add('promise', {
defer: true,
fn: function(deferred) {
a = 3
return Promise.resolve(a+2).then(res => deferred.resolve(res))
}
})
.add('bluebird', {
defer: true,
fn: function(deferred) {
a = 3
return Bluebird.resolve(a+2).then(res => deferred.resolve(res))
}
})
// add listeners
.on('cycle', event => console.log("%s", event.target))
.on('complete', function(){
console.log('Fastest is ' + this.filter('fastest').map('name'))
})
.on('error', error => console.error(error))
.run({ 'async': true })
Run Code Online (Sandbox Code Playgroud)
跑
? node promise_resolve.js
fn x 138,794,227 ops/sec ±1.10% (82 runs sampled)
cb x 3,973,527 ops/sec ±0.82% (79 runs sampled)
async x 2,263,856 ops/sec ±1.16% (79 runs sampled)
promise x 2,583,417 ops/sec ±1.09% (81 runs sampled)
bluebird x 3,633,338 ops/sec ±1.40% (76 runs sampled)
Fastest is fn
Run Code Online (Sandbox Code Playgroud)
如果您想更详细地比较各种promise和回调实现的性能/开销,请同时检查bluebirds基准测试。
file time(ms) memory(MB)
callbacks-baseline.js 154 33.87
callbacks-suguru03-neo-async-waterfall.js 227 46.11
promises-bluebird-generator.js 282 41.63
promises-bluebird.js 363 51.83
promises-cujojs-when.js 497 63.98
promises-then-promise.js 534 71.50
promises-tildeio-rsvp.js 546 83.33
promises-lvivski-davy.js 556 92.21
promises-ecmascript6-native.js 632 98.77
generators-tj-co.js 648 82.54
promises-ecmascript6-asyncawait.js 725 123.58
callbacks-caolan-async-waterfall.js 749 109.32
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1693 次 |
最近记录: |