console.log() async or sync?

JavascriptAsynchronous

Javascript Problem Overview


I am currently reading Async Javascript by Trevor Burnham. This has been a great book so far.

He talks about this snippet and console.log being 'async' in the Safari and Chrome console. Unfortunately I can't replicate this. Here is the code:

var obj = {}; 
console.log(obj); 
obj.foo = 'bar';
// my outcome: Object{}; 'bar';
// The book outcome: {foo:bar};

If this was async, I would anticipate the outcome to be the books outcome. console.log() is put in the event queue until all code is executed, then it is ran and it would have the bar property.

It appears though it is running synchronously.

Am I running this code wrong? Is console.log actually async?

Javascript Solutions


Solution 1 - Javascript

console.log is not standardized, so the behavior is rather undefined, and can be changed easily from release to release of the developer tools. Your book is likely to be outdated, as might my answer soon.

To our code, it does not make any difference whether console.log is async or not, it does not provide any kind of callback or so; and the values you pass are always referenced and computed at the time you call the function.

We don't really know what happens then (OK, we could, since Firebug, Chrome Devtools and Opera Dragonfly are all open source). The console will need to store the logged values somewhere, and it will display them on the screen. The rendering will happen asynchronously for sure (being throttled to rate-limit updates), as will future interactions with the logged objects in the console (like expanding object properties).

So the console might either clone (serialize) the mutable objects that you did log, or it will store references to them. The first one doesn't work well with deep/large objects. Also, at least the initial rendering in the console will probably show the "current" state of the object, i.e. the one when it got logged - in your example you see Object {}.

However, when you expand the object to inspect its properties further, it is likely that the console will have only stored a reference to your object and its properties, and displaying them now will then show their current (already mutated) state. If you click on the +, you should be able to see the bar property in your example.

Here's a screenshot that was posted in the bug report to explain their "fix":

So, some values might be referenced long after they have been logged, and the evaluation of these is rather lazy ("when needed"). The most famous example of this discrepancy is handled in the question https://stackoverflow.com/questions/4057440/is-chromes-javascript-console-lazy-about-evaluating-arrays

A workaround is to make sure to log serialized snapshots of your objects always, e.g. by doing console.log(JSON.stringify(obj)). This will work for non-circular and rather small objects only, though. See also https://stackoverflow.com/q/7389069/1048572.

The better solution is to use breakpoints for debugging, where the execution completely stops and you can inspect the current values at each point. Use logging only with serialisable and immutable data.

Solution 2 - Javascript

This isn't really an answer to the question, but it might be handy to someone who stumbled on this post, and it was too long to put in a comment:

window.console.logSync = (...args) => {
  try {
    args = args.map((arg) => JSON.parse(JSON.stringify(arg)));
    console.log(...args);
  } catch (error) {
    console.log('Error trying to console.logSync()', ...args);
  }
};

This creates a pseudo-synchronous version of console.log, but with the same caveats as mentioned in the accepted answer.

Since it seems like, at the moment, most browsers' console.log's are asynchronous in some manner, you may want to use a function like this in certain scenarios.

Solution 3 - Javascript

When using console.log:

a = {}; a.a=1;console.log(a);a.b=function(){};
// without b
a = {}; a.a=1;a.a1=1;a.a2=1;a.a3=1;a.a4=1;a.a5=1;a.a6=1;a.a7=1;a.a8=1;console.log(a);a.b=function(){};
// with b, maybe
a = {}; a.a=function(){};console.log(a);a.b=function(){};
// with b

in the first situation the object is simple enough, so console can 'stringify' it then present to you; but in the other situations, a is too 'complicated' to 'stringify' so console will show you the in memory object instead, and yes, when you look at it b has already be attached to a.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHelloWorldView Question on Stackoverflow
Solution 1 - JavascriptBergiView Answer on Stackoverflow
Solution 2 - JavascriptV. RubinettiView Answer on Stackoverflow
Solution 3 - JavascriptMiao SiyuView Answer on Stackoverflow