我应该从生产代码中删除console.log吗?

104

我目前在我的代码中随处都有这个JS语句:

window.console && console.log("Foo");

我想知道这是否会带来高昂的代价,在生产环境中是否有任何负面影响。

我是否可以继续留下客户端日志记录,还是应该删除?

编辑:最终,我认为我(以及其他人)能提出的最好论据是,留下日志记录可能会在服务器和客户端之间传输非常大量的额外数据。如果要完全优化生产代码,则需要删除日志记录以减少发送到客户端的 JavaScript 大小。


1
https://dev59.com/lXNA5IYBdhLWcg3wC5NR - Zach Lysobey
13个回答

53

另一种处理这个问题的方法是在控制台对象未定义时将其“存根化”,以便在没有控制台的上下文中不会抛出错误,即:

if (!window.console) {
  var noOp = function(){}; // no-op function
  console = {
    log: noOp,
    warn: noOp,
    error: noOp
  }
}

你可以想象一下...在各种控制台实现中定义了许多函数,因此您可以将它们全部存根化或仅存根化您使用的函数(例如,如果您只使用 console.log 而从未使用过 console.profileconsole.time 等)。

对我来说,这比在每个调用前添加条件或不使用它们更好。

另请参阅:在您的生产JavaScript代码中保留“console.log()”调用是个坏主意吗?


7
好主意,只需要做一些修正。Visual Studio JS调试器会在第一个console.log = noOp()处抛出异常,因为console对象本身未定义。我是这样解决的:console = { log: noOp, warn: noOp, error: noOp }。同时请注意,您不想在noOp后面加() - 您想要分配函数本身而不是它的返回值。已在Visual Studio JS调试器和IE9上进行了测试 - 现在它运行正常。 - JustAMartin
3
如果您已经在使用jQuery,他们提供了一个无操作函数:$.noop - crush

40

您不应该将开发工具添加到生产页面中。

回答另一个问题:代码不能有负面影响:

  • window.console如果未定义console,则为false
  • console.log(“Foo”)将在定义时打印消息到控制台(前提是页面没有使用非函数覆盖 console.log )。

49
我原则上同意你的观点。但是,我认为我们都会同意,在服务器端编程中,实现仅在调试模式下启用日志记录是确保高质量代码必要的步骤。没有人会在生产发布前删除其日志记录 - 程序会确定需要哪些日志记录级别并根据情况做出反应。我希望客户端编程中也有类似的东西......即使只设置一个“isDebug”变量,如果需要的话。为什么要让下一个开发人员承担负担,需要返回并重新添加有问题的区域的日志记录呢? - Sean Anderson
13
破旧到什么程度?我认为说开发者控制台是生产网站的一部分就像说日志文件是应用程序的一部分一样。是的,它们都是由代码生成的,但应该有一定的理解,即日志必须留在某个地方。虽然日志中的语句是否用户友好是另一回事。 - Sean Anderson
4
如何在最小化之前自动删除调试代码?客户端日志消息可能有很多种形式。 - Sean Anderson
6
你可以标记每一个调试代码,比如在调试代码前面/后面加上一个注释。例如:/*DEBUG:start*/console.log("Foo");/*DEBUG:end*/。然后,使用正则表达式删除所有出现的 /*DENUG-start*/[\S\s]*?/*DEBUG-end*/。最后,剩下的空白字符将会被压缩工具删除。 - Rob W
9
除非这个答案解释为什么不应该这样做,否则它没有任何用处。我们只是被要求盲目地接受它是不好的,没有证据或原因吗? - ESR
显示剩余9条评论

28

UglifyJS2

如果您正在使用这个压缩器,您可以设置 drop_console 选项:

将其设为true以丢弃对console.* 函数的调用

因此,我建议保留代码库中最繁琐的部分的 console.log 调用。


3
如果你正在使用_grunt_和_uglify_,同样的选项也可用(似乎uglify基于UglifyJS2): https://github.com/gruntjs/grunt-contrib-uglify#turn-off-console-warnings - Tilt
2
问题是“我应该吗”,而不是“我怎么做”。 - ESR
你应该保留 console.errors。如果生产环境中出现问题,那么你可以轻松地诊断它。不要删除 console.errors! - Oliver Watkins
如果需要的话,您可以将 drop_console 设置为 false,观察它们,然后再次隐藏它们。 - terales

16

如果缩小文件大小(minification)是你构建过程的一部分,你可以使用它来删除调试代码,如Google闭包编译器在这里所解释的: Exclude debug JavaScript code during minification

if (DEBUG) {
  console.log("Won't be logged if compiled with --define='DEBUG=false'")
}

如果你使用高级优化编译,这段代码甚至会被识别为死代码并完全删除。

7
不要把事情复杂化!在开发过程中,我个人一直都使用console.log,它真的能节省很多时间。对于生产环境,我只需要添加一行代码(在我的情况下是在“生产配置文件”中),将所有日志禁用即可。
window.console.log = () => {};

完成 ;) 这个monkey patches window.console 并用一个空函数替换 log 函数,禁用输出。

在大多数情况下,这对我来说已经足够好了。如果你想要“彻底”地从代码中删除console.logs以减小包的大小,你需要改变你的js打包方式(例如使用压缩工具丢弃console.logs)

此外,我认为你实际上可以为将它们保留在生产环境中提出有力的观点。对于普通用户来说,这不会改变任何事情,但确实可以加快理解奇怪的“异国浏览器”问题的速度。这不像后端日志可能包含关键信息。通过console.log显示的一切显然已经在前端可用!因此,不显示日志消息仅仅是因为你害怕透露安全细节之类的东西,这只是“安全性靠不透明性”的表现,应该让你思考为什么这些信息在前端首次可用!这只是我的意见。


5

一般而言,在生产代码中暴露日志消息并不是一个好主意。

理想情况下,您应该在部署之前使用构建脚本删除此类日志消息;但许多人(包括我)并不使用构建过程。

以下是我最近使用的一小段代码片段,用于解决这个问题。它修复了旧版IE中未定义的console引起的错误,并在“开发模式”下禁用日志记录。

// fn to add blank (noOp) function for all console methods
var addConsoleNoOp =  function (window) {
    var names = ["log", "debug", "info", "warn", "error",
        "assert", "dir", "dirxml", "group", "groupEnd", "time",
        "timeEnd", "count", "trace", "profile", "profileEnd"],
        i, l = names.length,
        noOp = function () {};
    window.console = {};
    for (i = 0; i < l; i = i + 1) {
        window.console[names[i]] = noOp;
    }
};

// call addConsoleNoOp() if console is undefined or if in production
if (!window.console || !window.development_mode) {
    this.addConsoleNoOp(window);
}

我很确定上面的addConsoleNoOp函数大部分内容来自 SO 网站上的另一个答案,但现在找不到了。如果我找到,稍后会添加一个参考链接。

编辑:这不是我想到的帖子,但以下是类似的方法:https://github.com/paulmillr/console-polyfill/blob/master/index.js


5
是的。在不支持它的浏览器中,console.log会抛出一个异常(控制台对象将无法找到)。

只要窗口被定义,他就不会进行短路评估。 - Joe
1
尽管我在最初的答案中忘记了它,但应该检查console.log。 - MK_Dev
我主要只是使用window.console来避免与IE发生麻烦。 我还没有遇到log被无意中覆盖的情况,但我相信这种情况可能会发生。 - Sean Anderson
1
@MK_Dev 具体来说,指的是哪些浏览器? - goodpixels
3
现在已经是2019年了,我怀疑没有任何浏览器不支持控制台。 - Oliver Watkins

3
var AppLogger = (function () {
  var debug = false;
  var AppLogger = function (isDebug) {
    debug = isDebug;
  }
  AppLogger.conlog = function (data) {
    if (window.console && debug) {
        console.log(data);
    }
  }
  AppLogger.prototype = {
    conlog: function (data) {
        if (window.console && debug) {
            console.log(data);
        }
    }
  };
return AppLogger;
})();

用法:

var debugMode=true;
var appLogger = new AppLogger(debugMode);
appLogger.conlog('test');

1

是的,使用console.log进行JavaScript调试是一个好习惯,但需要从生产服务器中删除,或者如果需要,在生产服务器上添加时需要考虑一些关键点:

**var isDebugEnabled="Get boolean value from Configuration file to check whether debug is enabled or not".**
if (window.console && isDebugEnabled) {
    console.log("Debug Message");
}

上述代码块必须在任何地方使用以进行日志记录,以首先验证当前浏览器是否支持控制台,以及调试是否已启用。

isDebugEnabled 必须根据我们的环境设置为 true 或 false。


1
如果使用正确的工具,如parcel/webpack,那么工作流就不再是头疼的问题了,因为在production构建中,console.log会被删除。即使在几年前使用Gulp/Grunt也可以自动化处理。

许多现代框架,如AngularReactSvelteVue.js都默认提供了这样的设置。基本上,只要部署正确的构建,即production构建,而不是仍然有console.logdevelopment构建,你就无需进行任何操作。


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