console.log会减慢JavaScript的执行性能吗?

142

console.log 调试功能的使用会降低 JavaScript 执行性能吗?它会影响生产环境中脚本执行的速度吗?

是否有一种方法可以从单个配置位置禁用生产环境中的控制台日志记录?


1
到目前为止,所有的答案都假设您只是输出字符串消息。那么日志对象的性能如何,可能具有大型对象结构?例如console.log(largeObj)? - PandaWood
2
将大量对象输出到控制台可能会将3秒的页面加载时间延长至30秒。这只是一个例子... - Andrew
1
一个简单的 console.log 需要约50毫秒。 - Pedram marandi
整个线程都散发着过早优化的气息。 - Kevin
12个回答

109

实际上,console.log 比一个空函数要慢得多。在 Chrome 38 上运行 这个 jsPerf 测试,结果令人惊讶:

  • 当浏览器控制台关闭时,调用 console.log 要比调用一个空函数慢大约 10,000 倍
  • 当控制台打开时,调用它甚至慢了 100,000 倍

如果您只有适量的 console.… 调用(例如一百次),您可能不会注意到性能延迟——我的 Chrome 安装程序上需要 2 毫秒(或在控制台打开时需要 20 毫秒)。但是,如果您反复记录信息到控制台,例如通过 requestAnimationFrame 连接它,那么它就会使事情变得卡顿。

更新:

在这个测试中,我还尝试了一个生产环境下的自定义“隐藏日志”——拥有一个变量来保存日志消息,按需提供。结果表明:

  • 比原生的 console.log 快大约 1,000 倍
  • 如果用户打开了他的控制台,则显然要快 10,000 倍。

2
当编译器遇到一个空函数时,它不会执行任何操作,而当它看到需要执行的代码行时,它将运行该函数。编译器为了优化程序,简单地不会运行空的、未使用的函数。 - SidOfc
1
@SidneyLiebrand 谢谢你的信息,这个很好知道。第二个测试的结果可以像 console.log 一样进行优化。它们都是产生副作用的函数。 - tomekwi
2
console.log本身并不会对性能产生太大的影响,除非将其绑定到滚动/调整大小处理程序上。这些处理程序会被频繁调用,如果您的浏览器需要每秒向控制台发送30/60次文本,那么可能会变得很丑陋。还有一个IE的bug,如果控制台关闭,则无法使用console.log。 :( - SidOfc
1
你说得完全正确 - 我在我的答案中也写了这个。作为一个经验法则,我尽量避免在生产代码中使用控制台调用。但性能并不是原因 - 而是因为“太容易让外行人阅读你的日志”,正如@Ramesh所写。 - tomekwi
2
四年后(查看@Ĭsααctիεβöss的评论),链接仍然无法使用。 - Aj Otto
显示剩余9条评论

76

如果您要在公共站点上使用它,任何具有使用开发人员工具的基本知识的人都可以阅读您的调试消息。根据您在记录什么,这可能不是一种理想的行为。

最好的方法之一是将console.log包装在其中一个方法中,并可以检查条件并执行它。在生产构建中,您可以避免拥有这些功能。这个Stack Overflow问题详细介绍了如何使用闭包编译器做同样的事情。

因此,回答您的问题:

  1. 是的,它会减慢速度,但只是微不足道的程度。
  2. 但是,不要使用它,因为很容易让人阅读您的日志。
  3. 这个问题的答案可能会给您提示,如何从生产环境中删除它们。

20
提示:使用 console.log 记录对象会导致内存泄漏,因为浏览器保留对象结构以允许开发人员展开日志。 - Shamasis Bhattacharya
4
@Gajus 您的编辑正在 Meta 上讨论 - Infinite Recursion
23
“一个人读取你的日志太容易了” — 这是什么问题?这是JavaScript,他们已经可以完全访问源代码了! - Quentin
4
为什么你会把你不信任客户的个人数据发送给客户呢?即使没有 console.log,他们也可以在“网络”选项卡中查看。 - Quentin
6
只是想插一句话:我刚刚发现,即使只是使用相同的静态文本(没有对象或数组;字面上只是console.log('test')),也会导致性能下降。 我注意到这一点是因为我正在记录一个在重新渲染期间调用了数百个React组件的函数中的“called”。仅仅存在日志记录代码就会在频繁更新期间导致非常明显的卡顿。 - SikoSoft
显示剩余8条评论

29
const DEBUG = true / false
DEBUG && console.log('string')

多么优雅的解决方案! - Systems Rebooter
3
缺少分号 ;) - trevorgk

20

使用调试功能console.log会降低JavaScript执行性能吗?它是否会影响生产环境中脚本执行的速度?

当然,console.log()会降低程序的性能,因为它需要计算时间。

是否有一种方法可以从单个配置位置禁用生产环境中的控制台日志记录?

将以下代码放在脚本开头,将标准的console.log函数覆盖为一个空函数即可。

console.log = function () { };

3
这似乎是在生产环境中禁用控制台日志最简单的解决方案之一。不知道为什么它没有得到更多关注!我们可以通过一个变量来控制这个空函数的定义,在不同的环境(生产或开发)中将其切换为true/false。 - Anshuman Manral
4
这个回答非常棒!谢谢! - Systems Rebooter

13

如果你在一个常见的核心脚本中创建控制台的快捷方式,例如:

var con = console;

然后在您的代码中使用 con.log("message") 或 con.error("error message"),在生产环境中,您可以简单地在核心位置重新连接 con:

var con = {
    log: function() {},
    error: function() {},
    debug: function() {}
}

16
脏代码:console.log = function(){} (该代码将禁用掉浏览器中的console.log函数) - br4nnigan

8
任何函数调用都会略微降低性能。但是少量的console.log不应该有任何明显的影响。
然而,在不支持console的旧浏览器中,它会抛出未定义的错误。

4

性能影响将是最小的,但在旧版本浏览器中,如果用户的浏览器控制台未打开,则会导致JavaScript错误log is not a function of undefined。 这意味着在console.log调用之后的所有JavaScript代码都不会执行。

您可以创建一个包装器来检查window.console是否为有效对象,然后在包装器中调用console.log。 像下面这样简单的东西就可以工作:

window.log = (function(console) {
    var canLog = !!console;
    return function(txt) {
        if(canLog) console.log('log: ' + txt);
    };
})(window.console);

log('my message'); //log: my message

这是一个示例:http://jsfiddle.net/enDDV/

3

我制作了这个jsPerf测试:http://jsperf.com/console-log1337

它似乎和其他函数调用一样不会花费更多时间。

如果有些浏览器没有控制台API怎么办? 如果你需要使用console.log进行调试,你可以在生产部署中包含一个脚本来覆盖控制台API,就像Paul在他的答案中建议的那样。


如果我可以选择两个答案,这个将会排在最前面。 - Sudantha
1
你的测试不仅添加了一个console.log调用,而且还执行了相同的jquery操作两次。我已经修改了你的测试,希望能有所帮助:http://jsperf.com/console-log1337/7 PS:谢谢,我之前不知道jsperf.com :) - dubrox
2
它看起来比普通函数调用要慢得多。在直接对决中,结果是无法比较的:http://jsperf.com/console-log1337/14 - tomekwi
1
错误的答案。根本不正确。只是一厢情愿的赞同,就像@tomekwi所展示的那样,差距是显著的。我已经进行了几次真实世界的测试,并且可以毫无疑问地说,滥用console.log肯定会导致性能下降。偶尔每秒记录几个日志没有什么大不了的,但如果频繁记录某些东西(在帧更新、重新渲染大型组件时),有和没有console.log的差别就像是白天和黑夜。 - SikoSoft

1
我这样做是为了保持控制台方法的原始签名。在一个常见的位置,加载在任何其他JS之前:
var DEBUG = false; // or true 

然后在整个代码中。
if (DEBUG) console.log("message", obj, "etc");
if (DEBUG) console.warn("something is not right", obj, "etc");

1
我更喜欢这样做:

我更喜欢这样做:

export const println = (*args,) => {
   if(process.env.NODE_ENV === "development") console.log(args)
}

然后在您的代码中到处使用println


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接