Webkit (Chrome, Safari) console.log is broken.

9 Comments

Chrome and Safari have a pretty serious bug where console.log() does not log variables as they are at the time of calling console.log(), but rather as they are some time in the future.  If you’re not aware of it, you can go insane trying to figure out where your code is going wrong, when actually console is logging values not-at-runtime.

Chrome logs the values of an object incorrectly.

This bug only affects (non-null) Objects and Arrays.

Logging Objects

First, let’s look at the logging of objects. When logging an object, Webkit’s console.log only prints a reference to that object in the log titled “Object”. It is not until you click on the arrow to expand it that it actually logs the data.

Consider:

1
2
3
4
5
6
(function(){
    var obj = {};
    console.log(obj);
    obj.new_value = "hello";
    console.log(obj);
})();

Here’s how Webkit logs it:

Chrome logs the values of objects not view-time, not at run-time.

And how FireBug does:

FireBug correctly logs objects at run-time.

As you can see, Webkit’s console.log() doesn’t correctly log object values.  This seems like a rather large and ridiculous oversight, especially if you consider what the point of console.log() is — to log the values of a variable.

 

Logging Arrays

With arrays, it’s even worse. The console dumps out the contents of the array.  However, it’s not clear (or guaranteed) what version of the array is being dumped. In most cases, it will just dump the latest version of the array referenced in console.log().

Consider:

1
2
3
4
5
6
7
8
(function(){
    var arr = [1];
    console.log("first: ", arr);
    arr.push(2);
    console.log("second: ", arr);
    arr.push(3);
    console.log("third: ", arr);
})();

Here’s how it’s logged in WebKit browsers:

WebKit logs incorrect array values when doing console.log()

 

And here’s how any sane developer would expect it to look like, in FireBug:

FireBug correctly logging an array with console.log()

 

Digging Deeper

With objects, the data is logged when we hit the expand arrow, but what about with arrays? If we call console.log, wait a little bit, then change the array, will it log the value when we called console.log(), or the new value?

Let’s experiment! Here’s code that sets various timeouts of 1, 2, 4, 8, … ms. When each timeout is executed, the 0th offset of the array is set to the actual amount of time elapsed, and console.log is called. If there’s a discrepancy between what we set the value to (the value at run-time), and the value logged, we’ll be able to see it. With enough delay, the two values should be equal.

Here’s some code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(function(){
    var arr = [];
    var update_array = function(){
        var time_since_start = (new Date()).getTime() - start_time;
        arr[0] = time_since_start;
        console.log("Value set to: " + time_since_start, arr);
    }

    var start_time = (new Date()).getTime();
    for (var i=0; i<=10; i++){
        var time = Math.pow(2, i);
        setTimeout(update_array, time);
    }
})();

In Chrome:

Chrome console.log() returns "future" values of arrays

In Safari:

Safari console.log shows "future" values of array.

And in FireBug:

FireBug accurately logs arrays with their run-time values.

What does this tell us?  In WebKit browsers, there’s clearly a delay between when we *call* console.log() and when the array is *actually* logged. It looks on my machine the delay is not constant, and is between 4ms and 16ms in Chrome, and about 2ms in Safari. Pretty strange stuff!

Incidentally, this also shows us the accuracy of various browsers’ setTimeouts. Chrome seems pretty spot-on — but I’d personally prefer to code in an environment with useful variable logging than one with ms-precision timeouts :)

About Sam

Sam is on the AppNexus UI team, with a focus on building out a modular, scalable, and developer-friendly framework. In addition to Javascript, he's fluent in PHP, MySQL, and will start with Python any day now. He also curates an assortment of items at his desk which includes several kinds of silly putty, a very tall tower of cans, and some gallium.

This entry was posted in Development Process, Javascript. Bookmark the permalink.

9 Comments
  • http://butlerpc.net Michael Butler

    Great find! I wonder if this has to do with the way Chrome’s V8 JavaScript engine works, pre-compiling code to make it run faster.

  • Michael

    Gosh I was just going totally nuts about this one!! This needs to be fixed asap…

  • Sam Mati

    Both FireBug and Chrome Dev Tools have their pros and cons. I’d agree that overall FireBug is better, however Chrome does have some nice features.

    Its stack trace and closure variables are quite useful, for example.

  • Cesium62

    Both FireBug and Chrome are crap. Neither wil display a grease monkey script. Neither can figure out the correct line number to display for a problem. Both suppress errors and console logging in strange and wonderful ways. Neither will let you find a function in the DOM and then set a breakpoint on that function.

  • Kevin Han

    Your second example (logging an array) now works for me in Chrome (19.0.1084.56). The first example is still broken, and the bug still exists when the array contains objects, it appears (that’s how I found this post). My workaround is to convert the array or object to a string before logging, but it is frankly shocking that this bug still exists; it seems like such an obvious defect but I can’t even find any mention of it on the Web other than this post.

  • marksyzm

    The bug still exists, and the only way I can think of to solve this issue is to create a deep clone of the object.

  • http://paulirish.com Paul Irish

    This is fixed. Try it in Chrome canary.

    • Phil Munro

      He’s right you know – it is fixed!

      great stuff – cheers Paul.

  • Andrii Nikitiuk

    I’m a bit late here..

    It’s not a bug, that’s the nature of console.log in chrome. Console.log is an asynchronous function, so by the time the actual output occurs the data can be already changed.