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


86

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

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

我想知道这是否昂贵,或在生产中有任何负面影响。

我可以随意离开客户端登录,还是应该退出?

编辑:最后,我想我(以及其他任何人?)可以提出的最佳论据是,通过保留日志消息,在服务器和客户端之间传输的额外数据的数量可能微不足道。要完全优化生产代码,必须删除日志记录,以减少发送给客户端的javascript的大小。


Answers:


41

你应该开发工具添加到生产页面。

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

  • window.console如果console未定义,将评估为false
  • console.log("Foo")将在定义消息后将消息打印到控制台(前提是该页面不会console.log被非功能覆盖)。

43
我原则上同意你的看法。但是,我想我们都同意,对于高质量的服务器端代码,实现除调试模式外不会触发的日志记录是必要的。没有人会删除生产版本的日志,程序会确定需要什么级别的日志并做出相应的反应。我希望对于客户端编程有一些类似的东西……如果需要的话,甚至只是设置一个“ isDebug”变量。我为什么要在将来需要重新返回并为有问题的区域重新添加日志记录的情况下,负担下一位开发人员的负担?
肖恩·安德森

11
破旧如何?我会说开发者控制台是生产网站的一部分,就像说日志文件是应用程序的一部分一样。是的,它们都是由代码生成的,但是应该对日志必须放在某个地方有一定的了解。但是,日志中的语句是否易于使用是另一回事。
肖恩·安德森

4
如何在最小化之前自动剥离调试代码?客户端日志消息可以采用多种形式。
肖恩·安德森

6
您可以标记每个调试代码,例如通过在注释的调试代码前添加前缀/后缀。范例:/*DEBUG:start*/console.log("Foo");/*DEBUG:end*/。然后,使用RegExp删除所有出现的/*DENUG-start*/[\S\s]*?/*DEBUG-end*/。其余的空白字符将被最小化器删除。
Rob W

3
除非此答案说出为什么不应该这样做,否则它实际上没有用。我们只是在没有证据或理由的情况下盲目接受它是不好的?
ESR

48

处理此问题的另一种方法是在未定义控制台对象时“存根”,因此在没有控制台的上下文中不会引发任何错误,即

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

您知道了...在控制台的各种实现上定义了很多功能,因此您可以将它们全部或仅使用的功能存根(例如,如果您仅使用过console.log而从未使用过console.profileconsole.time等等...)

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

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


6
好主意。仅需要一些修复。因为未定义控制台对象本身,所以Visual Studio JS调试器将在第一个console.log = noOp()处引发。我这样做是这样的:console = {log:noOp,警告:noOp,错误:noOp}。还要注意,您不想将()放在noOp之后-您要分配函数本身而不是其返回值。在Visual Studio JS调试器和IE9上进行了测试-现在可以正常使用了。
JustAMartin

3
仅供参考,如果您已经在使用jQuery,则它们提供了noop函数:$.noop
2015年

28

UglifyJS2

如果您使用的是这个缩小器,则可以设置drop_consoleoption

传递true以放弃对console。*函数的调用

因此,我建议保留 console.log呼叫,因为它们是代码库中最棘手的部分。


3
如果您使用的是gruntuglify,则也可以使用相同的选项(似乎uglify
倾斜

1
问题是“我应该”,而不是“我应该如何”。
ESR

您应该将console.errors保留在中。如果生产中的某人有问题,那么您可以轻松诊断。不要剥离console.errors!
奥利弗·沃特金斯

如果需要它们,则可以将其设置drop_consolefalse,观察它们并再次隐藏它们。
terales

16

如果缩小是构建过程的一部分,则可以使用它来去除调试代码,如Google封闭编译器在此处所述:在缩小过程中排除调试JavaScript代码

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

如果使用高级优化进行编译,则该代码甚至会被识别为无效代码并被完全删除


1
谢谢!我一直在寻找。:)
肖恩·安德森

5

是。在不支持console.log的浏览器中,console.log将引发异常(将找不到控制台对象)。


只要定义了窗口,就不会进行短路评估

1
尽管我在最初的答案中没有找到它,但也应该检查console.log。
MK_Dev 2011年

我主要只是执行window.console来防止IE麻烦。我还没有遇到日志被无意覆盖的情况,但是我敢肯定它会发生。
肖恩·安德森

@MK_Dev即,哪些浏览器?
goodpixels

现在是2019年。我怀疑是否有不支持控制台的浏览器。
奥利弗·沃特金斯

5

通常是的,在生产代码中公开日志消息不是一个好主意。

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

这是我最近一直在使用的一些代码的简短摘要,以解决这一难题。它修复了由console旧IE中未定义引起的错误,以及在“ development_mode”中禁用了日志记录。

// 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的另一个答案中提取了上述f'n的大部分内容,但现在无法找到。如果找到,我将在以后添加参考。

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


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

TL; DR

想法:记录对象可以防止它们被垃圾收集。

细节

  1. 如果将对象传递给 console.log对象,则可以通过DevTools控制台的引用来访问这些对象。您可以通过记录对象,对其进行变异并发现旧消息反映该对象的以后更改来进行检查。
  2. 如果日志太长,旧邮件确实会在Chrome中被删除。
  3. 如果日志很短,则旧消息不会被删除;如果这些消息引用对象,则这些对象不会被垃圾收集。

这只是一个主意:我检查了第1点和第2点,但没有检查3。

如果您想保留日志以进行客户端故障排除或其他需要,则:

['log', 'warn', 'error'].forEach( (meth) => {
  const _meth = window.console[meth].bind(console);
  window.console[meth] = function(...args) { _meth(...args.map((arg) => '' + arg)) }
});

0

我基本上用一个知道代码在哪里运行的函数来覆盖console.log函数。因此,我可以像往常一样继续使用console.log。它会自动知道我处于开发/质量保证模式或生产环境。还有一种强制的方法。这是一个工作的小提琴。 http://jsfiddle.net/bsurela/Zneek/

这是代码段,因为堆栈溢出是由发布jsfiddle的人暗示的

  log:function(obj)
{
    if(window.location.hostname === domainName)
    {
        if(window.myLogger.force === true)
        {
            window.myLogger.original.apply(this,arguments);
        }
    }else {
        window.myLogger.original.apply(this,arguments);
    }
},

0

我知道这是一个很老的问题,而且一段时间以来没有进行太多活动。我只想添加自己想出的解决方案,这对我来说似乎很好。

    /**
     * Logger For Console Logging 
     */
    Global.loggingEnabled = true;
    Global.logMode = 'all';
    Global.log = (mode, string) => {    
        if(Global.loggingEnabled){
            switch(mode){
              case 'debug':
                  if(Global.logMode == 'debug' || Global.logMode == 'all'){
                    console.log('Debug: '+JSON.stringify(string));
                  }
                  break;
              case 'error':
                  if(Global.logMode == 'error' || Global.logMode == 'all'){
                    console.log('Error: '+JSON.stringify(string));
                  }       
                  break;
              case 'info':
                  if(Global.logMode == 'info' || Global.logMode == 'all'){
                    console.log('Info: '+JSON.stringify(string));
                  }
                  break;
            }
        }
    }

然后,通常我会在这样的脚本中创建一个函数,或者可以在全局脚本中使它可用:

Something.fail = (message_string, data, error_type, function_name, line_number) => {
    try{

        if(error_type == undefined){
            error_type = 'error';
        }

        Global.showErrorMessage(message_string, true);
        Global.spinner(100, false);

        Global.log(error_type, function_name);
        Global.log(error_type, 'Line: '+line_number);
        Global.log(error_type, 'Error: '+data);

    }catch(error){
        if(is_global){
            Global.spinner(100, false);
            Global.log('error', 'Error: '+error);
            Global.log('error', 'Undefined Error...');
        }else{
            console.log('Error:'+error);
            console.log('Global Not Loaded!');
        }           
    }   
}

然后我只用它而不是console.log这样的:

try{
 // To Do Somehting
 Something.fail('Debug Something', data, 'debug', 'myFunc()', new Error().lineNumber);
}catch(error){
 Something.fail('Something Failed', error, 'error', 'myFunc()', new Error().lineNumber);
}

0

如果使用正确的工具(例如parcel/ )完成了工作流程,webpack那么不再麻烦,因为production构建console.log已被删除。甚至几年前与Gulp/Grunt它可能已经自动为好。

许多现代的框架如AngularReactSvelteVue.js来与设置外的开箱。基本上,只要部署正确的构建(即production一个development仍不存在的构建),您就无需执行任何操作console.log

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.