Google Chrome Console.Log() Inconsistency with Objects and Arrays

Google Chrome console.log() inconsistency with objects and arrays

After a lot of digging, I found that this has been reported as a bug, fixed in Webkit, but apparently not yet pulled into Google Chrome.

As far as I can tell, the issue was originally reported here: https://bugs.webkit.org/show_bug.cgi?id=35801 :

Description From mitch kramer 2010-03-05 11:37:45 PST

1) create an object literal with one or more properties

2) console.log that object but leave it closed (don't expand it in the console)

3) change one of the properties to a new value

now open that console.log and you'll see it has the new value for some reason, even though it's value was different at the time it was generated.

I should point out that if you open it, it will retain the correct value if that wasn't clear.

Response from a Chromium developer:

Comment #2 From Pavel Feldman 2010-03-09 06:33:36 PST

I don't think we are ever going to fix this one. We can't clone object upon dumping it into the console and we also can't listen to the object properties' changes in order to make it always actual.

We should make sure existing behavior is expected though.

A fix was implemented two and a half years later on August 9th, 2012 for Webkit ( http://trac.webkit.org/changeset/125174 ), but it does not appear to have made it into Chrome yet.

As of today, dumping an object (array) into console will result in objects' properties being
read upon console object expansion (i.e. lazily). This means that dumping the same object while
mutating it will be hard to debug using the console.

This change starts generating abbreviated previews for objects / arrays at the moment of their
logging and passes this information along into the front-end. This only happens when the front-end
is already opened, it only works for console.log(), not live console interaction.

Google Chrome's console.log() prints DOM nodes inconsistently

It is not a bug nor a feature but more of a trade-off. I gave an answer to a similar question about "how to", thus is was short. Here is about "why", so it needs more "academic" explanation.

It is related to how the Chromium DevTools logging work in union with the Blink engine, here is a simplified scenario for a DOM node:

console.log(document.querySelector('div'));

Blink V8::console.log -> IPC -> Chromium Process -> IPC -> DevTools front-end fork

That is, V8 executes console.log method implemented by Blink, which triggers a message for DevTools. That message is handled by IPC which in Blink is mainly asynchronous.
Once DevTools Console receives a Node object it must inspect the DOM Renderer to sync with it's actual render tree, so that when hovering on the node in the console the Renderer would highlight the node in browser page, so there it is:

DevTools inspect -> IPC -> Chromium Process -> IPC -> Blink DOM Render

Here is the problem, since the DOM Renderer is busy with synchronous style loading, in this specific case the render-blocking resource is link element, so it fails to respond timely and instead of render tree representation the console fallback to object representation of it, doing so instead of just showing a string representation gives the possibility to inspect that node anyway, a sane trade-off, albeit without the commodity of seeing it's mirror reference.

Additionally, other peculiarities of DevTools Console may be noted:

  • It does not really matter which console method was called, as they are mainly aliases for log level definition and not for special handling of object inspection, so console.error behaves the same for that reason.
  • DevTools inspect is issued only if Console tab is active or becomes active. So while it may show a object representation of node when performing the tests with an active Console tab, when performing them while being on another tab, let's say Performance, then switching to Console we can see those nodes appearing one by one as render tree, since by that time the DOM Render will be accessible.
  • A common myth about logged objects is that they mutates in the console when they are mutated by the JS runtime. Well, they are not. The Console creates a static "fingerprint" of object only for current level tree. It then creates a deeper tree on demand, when manually unfolding it, so it just uses for that new tree the current values which may give false impressions that it mutates the log.

I modified a bit the initial example, to be more like a "real" application, also to reveal the above behavior. Additionally, for more stress on render engine, it may be played with a x4 or x6 CPU throttling in the DevTools Performance tab.

<head>
<script>
document.addEventListener('DOMContentLoaded', () =>
console.log('DOMContentLoaded'));
</script>
<link rel="stylesheet" href="css.css">
</head>
<body>
<div></div>
<div></div>
<div></div>
<div></div>

<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script>
for (const div of document.querySelectorAll("div")) {
console.log(div);
}

let i = 1000, div, divs = [], ids = [];
while (i--) {
div = document.createElement('div');
div.textContent = new Date().toISOString();
document.body.appendChild(div);
if (!(i % 100)) {
const id = {id: i};
ids.push(id);
divs.push(div);
console.log(id, {div}, div);
}
}
setTimeout(() => {
for (const id of ids)
id.id = Math.random();

for (const div of divs) {
div.style.color = 'red';
const child = document.createElement('div');
child.textContent = 'OK';
div.appendChild(child);
}
}, 1000);
</script>
</body>

Inconsistency in JS console when adding arrays and objects

In your first example, it is just a block, so it is equivalent to running this code (the plus in front of the array literal converts it to a number):

{};
+[]; // 0

However, in your console.log code, it is considered an expression, so it is in fact an object literal. You can only pass expressions to functions, so this is the same.

function a(b) {return b;}
a({}+[]); // "[object Object]"

The addition operation converts them to a string, so that's why you get "[object Object]".

Inconsistent data in Chrome Developer Tools

This is because an element was removed from the array after the console.log().

Then you have expanded the array.

Just try this on the chrome console:

var myArray = ['value1', 'value2'];console.log(myArray);myArray.pop();

Why is chrome inspector showing one thing for an array but another when expanded | Vanilla JS

There have been answers to similar questions here and here.

Essentially the object printed to the console is "lazily" evaluated when you expand the object, so if a reference to that same object somewhere else in the code makes a change to the object, the values you see in the console upon expanding the object will reflect that change. This is assuming you're using the Chrome debugger which your screenshot looks like.

How can I debug why my array of objects have inconsistent values?

Try to use this instead

JSON.parse(JSON.stringify(var))

Full disclosure... I've never used vue.js in my life. But I believe this is just how Javascript objects work. Just because attribute_id shows as null inside the object doesn't mean it was null when the code was running. It doesn't mean it was changed within those 6 lines either.

Simplified example. But you can see the value in console reflects the change that was made after console.log.

Might be a bug in chrome?

Sample Image

Bug in JavaScript Google Chrome console when printing object

It is not a bug, console.log() works as per design.
If I understand correctly you want to see Objects in details for that use:

Option 1:

console.dir() to print browserable Object in chrome console.

For more information please check here : https://developer.mozilla.org/en-US/docs/Web/API/Console/dir

Option 2:

console.log(JSON.stringify());

This should also give you browserable Object.



Related Topics



Leave a reply



Submit