异步函数与同步函数相比具有固有的开销。虽然可以将所有内容都设为异步,但很可能会很快遇到性能问题。
同步 vs 异步
一个函数返回一个值。
一个异步
函数创建一个Promise对象来从函数中返回。Promise对象被设置为维护异步任务的状态并处理错误或后续的链接调用。承诺将在事件循环的下一个刻度中解决或拒绝。(如果您想要详细信息,请阅读规范)这相对于简单的函数调用和返回值具有内存和处理开销。
尽管量化开销有点无用,因为大多数异步函数是由于它们必须等待外部Node.js线程完成一些工作而异步的,通常是做缓慢的IO。与整个操作的时间相比,建立Promise的开销相当小,特别是如果替代方案是阻塞主JS线程。
另一方面,同步代码在主JS线程中立即运行。交叉区域是调度同步代码,无论是为了计时还是为了“节流”使用主JS线程,以便GC和其他异步任务有机会运行。
如果您在紧密的循环中逐个字符解析字符串,则可能不希望在每次迭代中创建一个Promise并等待其解决,因为完成该过程所需的内存和时间要求将很快爆炸。
另一方面,如果你的应用程序只是查询数据库并将结果转储到koa http响应中,那么你很可能会在异步promise中完成大部分操作(尽管在底层仍然有许多同步函数使其发生)。
愚蠢的例子
对一个人为制造的例子进行基准测试,比较同步返回和各种异步方法来解决相同的同步操作之间的差异。
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))
}
})
.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 })
运行
→ 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
如果您想更详细地比较各种Promise和Callback实现的性能/开销,请查看蓝鸟基准测试。
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
async function
也是异步的 - 非阻塞的,这就是Node.js并发的全部意义所在。 - Bergi