假设我们有一个像这样的函数:
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 开发人员在这里。简短的回答是“这取决于情况,不用担心”。
一般来说,V8(以及据我所知的其他引擎)会针对每个功能进行优化。所以,在你的例子中,如果foo
被优化了,它不知道它的返回值会被使用还是被忽略,所以它不能优化掉它。
异常(exception)情况是内联:优化编译器能够在优化调用函数时内联被调用的函数,例如在此示例中:
function foo() {
// Do some FOO work...
return {};
}
function bar() {
foo();
// Do some BAR work...
}
何时 foo
被优化后,它将(继续)返回一个新分配的空对象,无论它是从哪里调用的。当bar
已优化,编译器可能会决定内联 foo
,在这一步之后它会看到(它自己的假设函数的内部表示,例如):
function bar() {
// Do some FOO work...
{};
// Do some BAR work...
}
然后它可以轻松地将未使用的对象分配放在那里。
也就是说,正如对该问题的评论所指出的那样,这不是您需要担心的事情。 (除非您碰巧不必要地花费大量时间构建昂贵但未使用的返回值——但这似乎不太可能,因为这是相当明显的低效率,所以您很可能一开始就不会编写这样的代码。)
特别是,与不返回任何内容相比,返回您计算出的某个值的成本零,因为每个函数总是返回一些内容 - 如果它没有 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
替换空行之后的所有内容相比,该函数会稍稍(无法测量)慢 ,因为“空”else
-branch (自动插入 return undefined;
)不比 return result
快,因此评估 need_result
这种情况是浪费时间。
所以,简而言之:不用担心。编写有意义的代码,让引擎负责优化它。
(为了完整起见:如果您确实觉得需要进行手动优化工作,请通过测量来指导它:分析您的应用程序以查看大部分时间都花在哪里,并测量任何尝试更改的效果以查看它们是否有效是有效的。不要使用微基准,因为它们往往会产生误导。)
关于javascript - Javascript (V8) 是否优化未使用的返回值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62011982/