ฉันควรลบ console.log ออกจากรหัสการผลิตหรือไม่


88

ปัจจุบันฉันมีคำสั่ง JS นี้ทุกที่ในรหัสของฉัน:

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

ฉันสงสัยว่าสิ่งนี้มีค่าใช้จ่ายสูงหรือมีผลข้างเคียงเชิงลบในการผลิตหรือไม่

ฉันมีอิสระที่จะออกจากการเข้าสู่ระบบฝั่งไคลเอ็นต์หรือควรไป?

แก้ไข: ในท้ายที่สุดฉันคิดว่าข้อโต้แย้งที่ดีที่สุดที่ฉัน (และคนอื่น ๆ ?) สามารถเกิดขึ้นได้ก็คืออาจมีการถ่ายโอนข้อมูลเพิ่มเติมระหว่างเซิร์ฟเวอร์และไคลเอนต์จำนวนมากโดยทิ้งข้อความบันทึกไว้หาก รหัสการผลิตต้องได้รับการปรับให้เหมาะสมอย่างสมบูรณ์การบันทึกจะต้องถูกลบออกเพื่อลดขนาดของจาวาสคริปต์ที่ส่งไปยังไคลเอนต์


คำตอบ:


41

คุณไม่ควรเพิ่มเครื่องมือการพัฒนาในหน้าการผลิต

เพื่อตอบคำถามอื่น: รหัสไม่สามารถมีผลด้านลบ:

  • window.consoleจะประเมินเป็นเท็จหากconsoleไม่ได้กำหนดไว้
  • console.log("Foo")จะพิมพ์ข้อความไปยังคอนโซลเมื่อมีการกำหนด (โดยที่เพจไม่ได้เขียนทับconsole.logโดย non-function)

43
ฉันเห็นด้วยกับคุณในหลักการ แต่ฉันคิดว่าเราทุกคนยอมรับว่าการใช้การบันทึกที่ไม่เริ่มทำงานยกเว้นในโหมดดีบักเป็นสิ่งจำเป็นสำหรับโค้ดฝั่งเซิร์ฟเวอร์ที่มีคุณภาพ ไม่มีใครผ่านและลบการบันทึกของพวกเขาสำหรับรุ่นที่ใช้งานจริงโปรแกรมจะกำหนดระดับการบันทึกที่จำเป็นและตอบสนองตามนั้น ฉันหวังว่าจะมีบางอย่างที่คล้ายกับสิ่งนี้สำหรับการเขียนโปรแกรมฝั่งไคลเอ็นต์ ... แม้เพียงแค่ตั้งค่าตัวแปร "isDebug" หากจำเป็น เหตุใดฉันจึงต้องการสร้างภาระให้กับนักพัฒนาซอฟต์แวร์รายต่อไปโดยจำเป็นต้องย้อนกลับไปและเพิ่มการบันทึกใหม่สำหรับพื้นที่ที่มีปัญหาในอนาคต
Sean Anderson

11
โทรมยังไง? ฉันจะเถียงว่าการบอกว่าคอนโซลนักพัฒนาซอฟต์แวร์เป็นส่วนหนึ่งของเว็บไซต์ที่ใช้งานจริงก็เหมือนกับการบอกว่าไฟล์บันทึกเป็นส่วนหนึ่งของแอปพลิเคชัน ใช่ทั้งคู่สร้างขึ้นโดยรหัส แต่ควรมีความเข้าใจระดับหนึ่งว่าบันทึกจะต้องถูกทิ้งไว้ที่ใดที่หนึ่ง แม้ว่าข้อความภายในบันทึกจะใช้งานง่ายหรือไม่ก็เป็นอีกเรื่องหนึ่ง
Sean Anderson

4
วิธีหนึ่งจะตัดรหัสการดีบักโดยอัตโนมัติก่อนที่จะย่อเล็กสุด? มีรูปแบบจำนวนมากที่ข้อความบันทึกฝั่งไคลเอ็นต์อาจใช้
Sean Anderson

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.profileเท่านั้นconsole.timeฯลฯ ... )

สิ่งนี้สำหรับฉันเป็นทางเลือกที่ดีกว่าในการพัฒนามากกว่าการเพิ่มเงื่อนไขหน้าการโทรทุกครั้งหรือไม่ใช้

ดูเพิ่มเติม: เป็นความคิดที่ดีหรือไม่ที่จะปล่อยให้ "console.log ()" เรียกในโค้ด JavaScript ของผลิตภัณฑ์


6
ความคิดที่ดี. จำเป็นต้องแก้ไขบางอย่าง โปรแกรมดีบักเกอร์ Visual Studio JS พ่นที่ console.log = noOp () ตัวแรกเนื่องจากไม่ได้กำหนดออบเจ็กต์คอนโซลเอง ฉันทำแบบนี้ console = {log: noOp, warn: noOp, error: noOp} สังเกตด้วยว่าคุณไม่ต้องการใส่ () หลัง noOp - คุณต้องการกำหนดฟังก์ชันเองไม่ใช่ค่าส่งคืน ทดสอบบนโปรแกรมดีบักเกอร์ Visual Studio JS และ IE9 - ตอนนี้ใช้งานได้ดี
JustAMartin

3
FYI ถ้าคุณกำลังใช้ jQuery พวกเขาให้ฟังก์ชั่น noop $.noopนี้:
ขยี้

28

UglifyJS2

หากคุณกำลังใช้ minifier นี้คุณสามารถตั้งค่าdrop_consoleตัวเลือก :

ส่งผ่านจริงเพื่อยกเลิกการโทรไปยังฟังก์ชันคอนโซล *

ดังนั้นฉันขอแนะนำให้ออกจากการ console.logโทรเพราะเป็นส่วนที่ยากที่สุดของ codebase


3
หากคุณใช้คำรามและอัปลักษณ์ตัวเลือกเดียวกันนี้ก็มีให้ใช้งานเช่นกัน (ดูเหมือนว่า uglify จะขึ้นอยู่กับ UglifyJS2): github.com/gruntjs/…
เอียง

1
คำถามคือ "ฉันควร" ไม่ใช่ "ฉันจะทำอย่างไร"
ESR

คุณควรปล่อย console.errors ไว้ หากมีคนในการผลิตมีปัญหาคุณสามารถวินิจฉัยได้อย่างง่ายดาย อย่าถอดคอนโซลข้อผิดพลาด!
Oliver Watkins

หากจำเป็นสำหรับพวกเขาคุณสามารถตั้งค่าdrop_consoleเป็นfalseสังเกตและซ่อนอีกครั้ง
terales

16

หากการลดขนาดเป็นส่วนหนึ่งของกระบวนการสร้างของคุณคุณสามารถใช้เพื่อตัดโค้ดดีบักออกตามที่อธิบายไว้ที่นี่ด้วยคอมไพเลอร์การปิดของ Google: ยกเว้นโค้ด JavaScript สำหรับการดีบักในระหว่างการลดขนาด

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

หากคุณรวบรวมด้วยการเพิ่มประสิทธิภาพขั้นสูงรหัสนี้จะถูกระบุว่าตายและถูกลบออกทั้งหมด


1
ขอขอบคุณ! ฉันกำลังมองหาสิ่งนี้ :)
Sean Anderson

5

ใช่. console.log จะทำให้เกิดข้อยกเว้นในเบราว์เซอร์ที่ไม่รองรับ (จะไม่พบวัตถุคอนโซล)


ไม่ใช่กับการประเมินการลัดวงจรของเขาตราบใดที่มีการกำหนดหน้าต่างไว้
โจ

1
แม้ว่าฉันจะพลาดไปในคำตอบเริ่มต้น แต่ควรตรวจสอบ console.log ด้วย
MK_Dev

ส่วนใหญ่ฉันทำ window.console เพื่อป้องกันไม่ให้ยุ่งยากกับ IE ฉันยังไม่เจอสถานการณ์ที่บันทึกถูกลบล้างโดยไม่ได้ตั้งใจ แต่ฉันแน่ใจว่ามันอาจเกิดขึ้นได้
Sean Anderson

@MK_Dev ได้แก่ เบราว์เซอร์ใด
goodpixels

เป็นปี 2019 ฉันสงสัยว่ามีเบราว์เซอร์ใดบ้างที่ไม่รองรับคอนโซล
Oliver Watkins

5

โดยทั่วไปใช่ไม่ใช่ความคิดที่ดีที่จะเปิดเผยข้อความบันทึกในรหัสการผลิตของคุณ

ตามหลักการแล้วคุณควรลบข้อความบันทึกดังกล่าวด้วยบิลด์สคริปต์ก่อนการปรับใช้ แต่หลายคน (ส่วนใหญ่) ไม่ใช้กระบวนการสร้าง (รวมถึงฉัน)

นี่คือตัวอย่างสั้น ๆ ของโค้ดบางส่วนที่ฉันใช้เมื่อไม่นานมานี้เพื่อแก้ปัญหาที่กลืนไม่เข้าคายไม่ออกนี้ แก้ไขข้อผิดพลาดที่เกิดจากconsoleIE เก่าที่ไม่ได้กำหนดไว้ตลอดจนปิดใช้งานการบันทึกหากอยู่ใน "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);
}

ฉันค่อนข้างแน่ใจว่าฉันเอาaddConsoleNoOpf'n ข้างต้นมาจากคำตอบอื่นใน SO แต่หาไม่ได้ในตอนนี้ ฉันจะเพิ่มข้อมูลอ้างอิงในภายหลังหากพบ

แก้ไข: ไม่ใช่โพสต์ที่ฉันคิด แต่เป็นแนวทางที่คล้ายกัน: 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เพื่อวัตถุประสงค์ในการดีบักจาวาสคริปต์ แต่จำเป็นต้องลบออกจากเซิร์ฟเวอร์ที่ใช้งานจริงหรือหากจำเป็นสามารถเพิ่มบนเซิร์ฟเวอร์ที่ใช้งานจริงโดยมีประเด็นสำคัญบางประการที่ต้องพิจารณา:

**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 ต้องตั้งค่าเป็นจริงหรือเท็จตามสภาพแวดล้อมของเรา


1

TL; ดร

แนวคิด:การบันทึกอ็อบเจ็กต์ป้องกันไม่ให้ถูกเก็บรวบรวมขยะ

รายละเอียด

  1. หากคุณส่งผ่านวัตถุไปยังวัตถุconsole.logเหล่านี้จะสามารถเข้าถึงได้โดยการอ้างอิงจากคอนโซลของ DevTools คุณสามารถตรวจสอบได้โดยบันทึกวัตถุกลายพันธุ์และพบว่าข้อความเก่าแสดงถึงการเปลี่ยนแปลงของวัตถุในภายหลัง
  2. หากบันทึกยาวเกินไปข้อความเก่าจะถูกลบใน Chrome
  3. หากบันทึกสั้นข้อความเก่าจะไม่ถูกลบออกหากข้อความเหล่านี้อ้างอิงวัตถุวัตถุเหล่านี้จะไม่ใช่ Garbage Collected

เป็นเพียงแนวคิด:ฉันตรวจสอบจุด 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 ได้เหมือนเดิม โดยอัตโนมัติรู้ว่าฉันอยู่ในโหมด dev / qa หรือในการผลิต ยังมีวิธีบังคับอีกด้วย นี่คือซอที่ใช้งานได้ 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มันอาจจะได้รับโดยอัตโนมัติเช่นกัน

หลายกรอบที่ทันสมัยเช่นAngular, React, Svelte, Vue.jsมาพร้อมกับการตั้งค่าที่ออกจากกล่อง โดยพื้นฐานแล้วคุณไม่ต้องทำอะไรเลยตราบใดที่คุณปรับใช้บิลด์ที่ถูกต้องนั่นคือproductionสิ่งdevelopmentที่ยังคงมีconsole.logอยู่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.