Javascript 我应该从生产代码中删除console.log吗?
目前,我的代码中到处都有这个JS语句:Javascript 我应该从生产代码中删除console.log吗?,javascript,logging,Javascript,Logging,目前,我的代码中到处都有这个JS语句: window.console && console.log("Foo"); 我想知道这是昂贵的,还是在生产中有任何负面的副作用 我可以让客户端登录,还是应该让客户端登录 编辑:最后,我想我(还有其他人?)能想到的最好的论据是,在服务器和客户机之间传输的额外数据量可能是不可忽略的,因为在服务器和客户机之间留下了日志消息。如果要完全优化生产代码,则必须删除日志记录以减小发送到客户端的javascript的大小。您应该而不是将开发工具添加到生产
window.console && console.log("Foo");
我想知道这是昂贵的,还是在生产中有任何负面的副作用
我可以让客户端登录,还是应该让客户端登录
编辑:最后,我想我(还有其他人?)能想到的最好的论据是,在服务器和客户机之间传输的额外数据量可能是不可忽略的,因为在服务器和客户机之间留下了日志消息。如果要完全优化生产代码,则必须删除日志记录以减小发送到客户端的javascript的大小。您应该而不是将开发工具添加到生产页面 要回答另一个问题:代码不能有负面的副作用:
将计算为false窗口。如果未定义
,则控制台控制台
将在定义消息时将消息打印到控制台(前提是页面不会被非函数覆盖console.log(“Foo”)
)console.log
是的。console.log将在不支持它的浏览器中引发异常(找不到console对象)。另一种处理方法是在未定义console对象时将其“存根”,以便在没有控制台的上下文中不会引发错误,即
if (!window.console) {
var noOp = function(){}; // no-op function
console = {
log: noOp,
warn: noOp,
error: noOp
}
}
你明白了。。。控制台的各种实现上定义了许多函数,因此您可以将它们全部存根,也可以仅存根于您使用的函数(例如,如果您只使用过console.log
,而从未使用过console.profile
,console.time
等)
对我来说,这是一个比在每次调用之前添加条件或不使用条件更好的开发选择
另请参见:如果缩小是构建过程的一部分,您可以使用它删除调试代码,如Google closure compiler所述: 如果使用高级优化进行编译,此代码甚至会被标识为死代码并完全删除是的,使用
console.log
进行javascript调试是一种很好的做法,但需要将其从生产服务器中删除,或者如果需要,可以将其添加到生产服务器上,并考虑以下要点:
必须在任何地方使用上述代码块进行日志记录,以便首先验证当前浏览器是否支持控制台以及是否启用了调试
isDebugEnabled
必须根据我们的
环境
通常是的,在生产代码中公开日志消息不是一个好主意 理想情况下,您应该在部署之前使用构建脚本删除此类日志消息;但是许多(大多数)人不使用构建过程(包括我) 下面是我最近用来解决这个难题的一些代码的一小段。它修复了旧IE中未定义的
控制台所导致的错误,以及在“开发”模式下禁用日志记录
//fn为所有控制台方法添加blank(noOp)函数
var addConsoleNoOp=函数(窗口){
变量名称=[“日志”、“调试”、“信息”、“警告”、“错误”,
“assert”、“dir”、“dirxml”、“group”、“groupEnd”、“time”,
“timeEnd”、“count”、“trace”、“profile”、“profileEnd”],
i、 l=名称。长度,
noOp=函数(){};
window.console={};
对于(i=0;i
我很确定我从另一个答案中获得了上面的大部分addConsoleNoOp
f'n,但是现在找不到。如果我找到它,我会在以后添加一个引用
编辑:这不是我想到的帖子,但这里有一个类似的方法:我基本上用一个知道代码运行位置的函数覆盖console.log。因此,我可以像往常一样继续使用console.log。它自动知道我处于开发/质量保证模式或生产模式。还有一种方法可以强迫它。
这是一把小提琴。
下面是一段代码,因为发布JSFIDLE的人暗示堆栈溢出
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);
}
},
丑陋的JS2
如果您正在使用此迷你型,则可以设置:
传递true以放弃对控制台的调用。*函数
因此,我建议将console.log
调用保留为代码库中最棘手的部分
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;
})();
用法:
TL;博士
Idea:日志对象阻止它们被垃圾收集
细节
如果您将对象传递给console.log
,则可以从DevTools的控制台引用这些对象。您可以通过记录对象、对其进行变异并发现旧消息反映了对象后来的更改来检查它
如果日志太长,旧消息会在Chrome中被删除
如果日志很短,则不会删除旧消息;如果这些消息引用对象,则不会对这些对象进行垃圾收集
这只是一个想法:我检查了第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)) }
});
我知道这是一个很老的问题,已经有一段时间没有太多活动了。我只是想添加我提出的解决方案,它似乎对我很有效
/**
* 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);
}
如果使用正确的工具(如packet
/webpack
)完成工作流,那么这就不再是一件令人头痛的事,因为生产构建控制台时,日志将被删除。甚至在几年前,我们还喝了一大口
/
['log', 'warn', 'error'].forEach( (meth) => {
const _meth = window.console[meth].bind(console);
window.console[meth] = function(...args) { _meth(...args.map((arg) => '' + arg)) }
});
/**
* 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!');
}
}
}
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);
}