Javascript (V8) 是否优化未使用的 return 值
Does Javascript (V8) optimizes unused return values
假设我们有这样一个函数:
function foo() {
// do some work...
return () => {}; // foo returns a function
}
客户端代码可以在两种情况下使用foo
:
- 使用函数的结果
const result = foo();
// some code that uses result...
- 忽略函数的结果
foo();
我想知道运行时(我不想引用语言本身,因为这很可能是依赖于实现的)是否会优化第一种情况,所以我不必像这样自己做:
function foo(needTheResultValue = false) {
// do some work...
if (needTheResultValue) return () => {};
// nothing is returned if the caller didn't ask for it
}
这里是 V8 开发人员。简短的回答是 "it depends, don't worry about it".
一般来说,V8(和其他引擎,据我所知)在每个函数的基础上进行优化。所以,在你的例子中,如果 foo
被优化,它不知道它的 return 值是被使用还是被忽略,所以它不能优化它。
内联是个例外:优化编译器能够在优化调用函数时内联被调用函数,例如在这个例子中:
function foo() {
// Do some FOO work...
return {};
}
function bar() {
foo();
// Do some BAR work...
}
当 foo
被优化时,它将(继续)return 一个新分配的空对象,无论从哪里调用它。当 bar
被优化时,编译器可能决定内联 foo
,并且在那一步之后它看到(它自己的假设函数的内部表示):
function bar() {
// Do some FOO work...
{};
// Do some BAR work...
}
然后它可以轻松地将未使用的对象分配放在那里。
也就是说,正如对该问题的评论所指出的,这不是您需要担心的事情。 (除非你碰巧不必要地花费大量时间来构建昂贵但未使用的 return 值——但这似乎不太可能,因为这是一个相当明显的低效率,所以你很可能一开始就不会编写这样的代码.)
特别是,return与return什么都不做相比,return你已经计算出的一些值的成本为零,因为每个函数总是returns something -- 如果它没有 return
语句,那么引擎会悄悄地为你插入一个 return undefined;
。这意味着 function f1() {}
和 function f2() { return undefined; }
将编译为完全相同的代码。如果你决定写这样的东西:
function overly_clever(need_result) {
let result = do_some_work();
if (result < 0) handle_error();
if (need_result) {
return result;
} else {
// Return nothing.
}
}
那么这个函数会比用简单的 return result
替换空行后的所有内容慢慢,因为 "empty" else
-分支(自动插入 return undefined;
)并不比 return result
快,因此评估 need_result
条件是浪费时间。
所以,简而言之:别担心。编写有意义的代码,让引擎负责优化它。
(为了完整起见:如果您确实觉得需要进行手动优化工作,请通过测量来指导它:分析您的应用以查看大部分时间花费在何处,并测量任何尝试更改的效果以查看如果它们有效。不要使用微基准测试,因为它们往往会产生误导。)
假设我们有这样一个函数:
function foo() {
// do some work...
return () => {}; // foo returns a function
}
客户端代码可以在两种情况下使用foo
:
- 使用函数的结果
const result = foo();
// some code that uses result...
- 忽略函数的结果
foo();
我想知道运行时(我不想引用语言本身,因为这很可能是依赖于实现的)是否会优化第一种情况,所以我不必像这样自己做:
function foo(needTheResultValue = false) {
// do some work...
if (needTheResultValue) return () => {};
// nothing is returned if the caller didn't ask for it
}
这里是 V8 开发人员。简短的回答是 "it depends, don't worry about it".
一般来说,V8(和其他引擎,据我所知)在每个函数的基础上进行优化。所以,在你的例子中,如果 foo
被优化,它不知道它的 return 值是被使用还是被忽略,所以它不能优化它。
内联是个例外:优化编译器能够在优化调用函数时内联被调用函数,例如在这个例子中:
function foo() {
// Do some FOO work...
return {};
}
function bar() {
foo();
// Do some BAR work...
}
当 foo
被优化时,它将(继续)return 一个新分配的空对象,无论从哪里调用它。当 bar
被优化时,编译器可能决定内联 foo
,并且在那一步之后它看到(它自己的假设函数的内部表示):
function bar() {
// Do some FOO work...
{};
// Do some BAR work...
}
然后它可以轻松地将未使用的对象分配放在那里。
也就是说,正如对该问题的评论所指出的,这不是您需要担心的事情。 (除非你碰巧不必要地花费大量时间来构建昂贵但未使用的 return 值——但这似乎不太可能,因为这是一个相当明显的低效率,所以你很可能一开始就不会编写这样的代码.)
特别是,return与return什么都不做相比,return你已经计算出的一些值的成本为零,因为每个函数总是returns something -- 如果它没有 return
语句,那么引擎会悄悄地为你插入一个 return undefined;
。这意味着 function f1() {}
和 function f2() { return undefined; }
将编译为完全相同的代码。如果你决定写这样的东西:
function overly_clever(need_result) {
let result = do_some_work();
if (result < 0) handle_error();
if (need_result) {
return result;
} else {
// Return nothing.
}
}
那么这个函数会比用简单的 ,因为 "empty" 所以,简而言之:别担心。编写有意义的代码,让引擎负责优化它。 (为了完整起见:如果您确实觉得需要进行手动优化工作,请通过测量来指导它:分析您的应用以查看大部分时间花费在何处,并测量任何尝试更改的效果以查看如果它们有效。不要使用微基准测试,因为它们往往会产生误导。)return result
替换空行后的所有内容慢慢else
-分支(自动插入 return undefined;
)并不比 return result
快,因此评估 need_result
条件是浪费时间。