1

When I do:

<!DOCTYPE html>
<html><head><title></title></head>
<body>
    <div id="root"></div>
    <script>
        let a = document.getElementById('root');
        console.log(a);
        a.append('cat');
        console.log(a);
    </script>
</body></html>

I expect the console to be:

<div id="root"></div>
<div id="root">cat</div>

But I get:

<div id="root">cat</div>
<div id="root">cat</div>

Its like the .append('cat') command runs before the first console.log() command. How is this? I thought programming code was always executed sequentially. Where can I learn which code executes sequentially and which ones don't in Javascript?

This might be a problem if I'm trying to debug more complex code later.

  • 1
    This is probably a quirk of the browser console and how it displays the objects relative to when the log is executed. Print the `outerHTML` instead, e.g. `a.outerHTML`. – MinusFour Jan 21 '21 at 00:40
  • It's not a quirk, its a feature. `a` was declared by reference so it's showing `a`'s current value. Agree with @MinusFour in that "outerHTML" will log the "state" at that moment in this case – GetSet Jan 21 '21 at 00:45
  • @GetSet it is not showing its current value at the time console.log was called though. – Daniel Jan 21 '21 at 00:46
  • Chrome does the same thing, I see your point @Daniel – GetSet Jan 21 '21 at 00:47
  • It kinda makes sense tho why Chrome would do it this way. Its by reference. Every "pointer" pointing to that reference is going to change when the original source of truth changes. The console.log was on the reference. The reference value changed. – GetSet Jan 21 '21 at 00:50
  • possible duplicate of [console.log() async or sync?](https://stackoverflow.com/q/23392111/1048572) – Bergi Jan 21 '21 at 01:12
  • @Bergi, OP's code is strictly sequential (in a "procedural" sense). The consensus is its a browser feature or defect regarding `console.log()`. At least so far here who weighed on this thread – GetSet Jan 21 '21 at 01:16
  • @GetSet Exactly that's what the linked thread explains. I'm just not certain whether the special handling of DOM elements in particular warrants a more specific answer – Bergi Jan 21 '21 at 01:20
  • maybe more relevant: [Are DOM elements passed by reference to console.log?](https://stackoverflow.com/q/25840318/1048572) – Bergi Jan 21 '21 at 01:50
  • Found this: https://developer.mozilla.org/en-US/docs/Web/API/Console/log explains the discrepancies – GetSet Jan 22 '21 at 00:10

1 Answers1

1

I am using firefox and I am getting the expected output of (in stackOverflow). However innerText and innerHTML are logging with the same "unexpected behavior" that you are experiencing when run as a .html document.

<div id="root"></div>
<div id="root">cat</div>

It appears that the "problem" is due to the console logs of html nodes from the DOM referencing the DOM in real time. Therefore if you change the node, the console log will UPDATE to show that change.
You should therefore not console log nodes if time specific console logs of old nodes is important information to you. Instead us innerHTML to get the information as an immutable string that will not update along with the nodes.

<!DOCTYPE html>
<html><head><title></title></head>
<body>
    <div id="root"></div>
    <script>
        let a = document.getElementById('root');
        console.log(a);
        a.append('cat');
        console.log(a);
    </script>
</body></html>
Daniel
  • 1,392
  • 1
  • 5
  • 16
  • I thought about the "event loop" aspect and put a timeout on the 2nd console.log, no change in output in Chrome – GetSet Jan 21 '21 at 00:49
  • 1
    Shouldn't you have put both a.append('cat') as well as the second console log in a timeout? To ensure that the first one fires in a different cycle of the event loop. – Daniel Jan 21 '21 at 00:56
  • Well, I negated that option by adding in at the end a `a.append('dog')`. Unsurprisingly, all the console.logs had "dog" too. But I guess thats worth looking into. – GetSet Jan 21 '21 at 00:57
  • interestingly if you use a.innerHTML in the console log it works as expected – Daniel Jan 21 '21 at 01:02
  • Yeah I noticed that too from @MinusFour original comment above to OP. It makes that it would since now another method (or property) is returning it's value, as opposed to re-running each time on a value change. There MinusFour, mentioned `outerHTML`. – GetSet Jan 21 '21 at 01:04
  • It appears to be that the document objects that are logged are in real time referencing the DOM. So when making changes to the DOM the console logs are changing as well. – Daniel Jan 21 '21 at 01:10
  • Precisely. That does seem to be the case. At least in Chrome (Version 87.0.4280.141 (Official Build) (64-bit)) – GetSet Jan 21 '21 at 01:11
  • I updated my answer to reflect this comment chain. I experience this behavior in Firefox v84.0.2 as well. (Just not in stackoverflow code snippet running) – Daniel Jan 21 '21 at 01:21
  • @GetSet The timeout approach works, it just needs to be a considerable timeout. When trying with values around 100ms, I even get a clear race condition - sometimes the console displays the old value, sometimes the new one. With >200ms, it always logs the empty div first. – Bergi Jan 21 '21 at 01:54
  • Yeah but @Bergi my test was at 1000ms. Taking your advice (and logic), I put it at 10,000ms and just waited: and the former console.log did not update with the new value, So i see your point – GetSet Jan 21 '21 at 02:57
  • @GetSet I executed the snippet directly from the console. If you put it in the html page, the element will probably only get rendered in the console when you open the devtools, so you either need to be quick about that or always keep them open. – Bergi Jan 21 '21 at 02:59
  • @Bergi Yes I had dev tools open. The code was from a test html file. Like you said though or hinted at, there is some "feedback loop" as it pertains to console.log. The 10s did the trick on my machine: showed different results on console.log – GetSet Jan 21 '21 at 03:02