DEV Community

Adam Crockett ๐ŸŒ€
Adam Crockett ๐ŸŒ€

Posted on • Updated on

console.log is slow

Im not kidding, your code might not actually be slow, take out your console logs and never benchmark with them inside the code exec, its staggeringly slow.

Edit: kudos DeChamp for this high level reporting although you should run your own tests there are plenty of ideas in the comments, enjoy!

Damn sure enough, it's pretty slow.

10000 rows.

with console
422.90000000596046
410.90000000596046
437.30000001192093

without
0.30000001192092896
0.4000000059604645
0.10000002384185791

Top comments (50)

Collapse
 
thatambuj profile image
Ambuj Singh

The real reason behind this is that console.log is actually synchronous and mixing sync with async is pretty bad in any language or runtime. People should use something like opentelemetry-js or other telemetry tools for logging instead of console.logs.

Collapse
 
adam_cyclones profile image
Adam Crockett ๐ŸŒ€

Could be but if you move a console.log into an async function theoretically you wonโ€™t be blocking and you wonโ€™t get the slow down correct? I think thereโ€™s more at work here related to the DOM which others have mentioned but equally it might well be this, either way Iโ€™m interested in the problem ๐Ÿ˜Š

Collapse
 
lulebe profile image
Leander Berg

Oh no, massive misunderstanding. Async functions do not make anything asynchronous. JavaScript is still single threaded. The only thing they do is making the syntax around using promises or callbacks easier. But a synchronous function like console.log (see, it has no promise) doesn't suddenly turn into an asynchronous one by wrapping it in async. I really suggest you read up on how async/await works because you might be making a lot of mistakes in your code.

Thread Thread
 
brense profile image
Rense Bakker

Whether JavaScript is single threaded depends on the runtime. JS in the browser is single threaded, but NodeJS can be multi threaded. The async keyword does infact mean your function is wrapped in a promise. developer.mozilla.org/en-US/docs/W...

Thread Thread
 
adam_cyclones profile image
Adam Crockett ๐ŸŒ€

Iโ€™m sorry Iโ€™m using slang for asynchronous not referring to async await

Thread Thread
 
adam_cyclones profile image
Adam Crockett ๐ŸŒ€ • Edited

Furthermore Iโ€™ve been a JavaScript developer for 10 years I understand the call stack and event loop ๐Ÿ˜ญ๐Ÿ˜‚ (thanks for the giggle)

Thread Thread
 
brense profile image
Rense Bakker

async/await refers to asynchronous...

Thread Thread
 
brense profile image
Rense Bakker

Ok mate, whatever, go read these articles anyways:
educative.io/answers/are-asynchron...
developer.mozilla.org/en-US/docs/L...

Because what you claimed was dead wrong. Not even any discussion ๐Ÿคท

Thread Thread
 
adam_cyclones profile image
Adam Crockett ๐ŸŒ€

But I havenโ€™t made any claim?

 
ipwright83 profile image
Ian Wright

@lulebe is correct though, wrapping something in a promise doesn't magically make it asynchronous. I believe all Promises also immediately execute, so it won't actually make any difference wrapping it.

Also to be clear the JS event loop in Node is single threaded (unless you use worker threads), it's just part of the internals (C++ I imagine) allows you to process I/O etc in another thread leaving the JS to keep executing.

Thread Thread
 
brense profile image
Rense Bakker

People here are mixing up parallelism and asynchronisity. Recommend everyone read these articles:
educative.io/answers/are-asynchron...
developer.mozilla.org/en-US/docs/L...

And no, @lulebe is not correct. Async does infact make your function asynchronous. It wraps your function in a promise, making it non-blocking, or in other words: the next line of code will execute, without waiting for the result of the previous line. No, it will not make your code execute in another thread.

As for NodeJS... NodeJS itself is multi-threaded, meaning it CAN access multiple cores. It does however execute your javascript code in a single thread, unless you use worker threads yes.

Thread Thread
 
ipwright83 profile image
Ian Wright • Edited

It makes the asynchronous bits inside non-blocking sure (network requests/disk IO). But anything synchronous will still be blocking...

For example run the following, which simulates a slow operation (which is what the article is referring to with the console.log, exaggerated somewhat). There's a significant delay before 3 is logged to the console (tested in JSFiddle).

If however the for loop were replaced with some disk IO instead, then 3 would be logged immediately.

async function two() {
    console.log(2);
  for(let i = 0; i < 10000000000; i++) {}
}

(async function() {
  console.log(1);

  await two();

  console.log(3);
})();
Enter fullscreen mode Exit fullscreen mode

So I still think the comment is correct, that the two function is blocking due to the sync nature of the slow bit. Unless I'm mis-understanding the point you're trying to make?

Thread Thread
 
adam_cyclones profile image
Adam Crockett ๐ŸŒ€

Here is a relaxing cat picture to help everyone feel good ๐Ÿ˜Š I have no further input
Image description

Thread Thread
 
brense profile image
Rense Bakker

Yes, the for loop will hang up the thread. async/await is not a method to do parallel execution of code, it doesnt allow you to run multiple threads to do expensive calculations, like doing a for loop one million times. I was purely replying to this claim of yours:

But a synchronous function like console.log (see, it has no promise) doesn't suddenly turn into an asynchronous one by wrapping it in async.

My point was: Yes thats exactly what async does. It wraps whatever you put in it with a promise, making the code non-blocking (asynchronous):

async function two(){
  // await makes this line blocking, within the context of this function
  await new Promise(resolve => {
    // wait for something before resolving
    setTimeout(() => resolve(), 100)
  })
  console.log('finished waiting') // this line didnt block anything
}

console.log('beginning')
two() // returns a promise, doesnt block execution of next line unless you use await
console.log('end')
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
brense profile image
Rense Bakker

Judging from your examples, what you mean is that the execution of the for loop will keep the main thread busy, making it unable to execute the next line of code. Thats why I tried to clarify that I think there is some confusion about the differences between parallelism and asynchronisity. Nothing in JS except worker threads in NodeJS, will create a new thread, allowing for true parallel execution of code. So when a line of code is keeping the main thread occupied (like when you loop over something a million times), it will freeze up your program. Asynchronous execution of code is a different concept. It just means that not every line of code has to be executed in a chronological order and you can do that in JS with promises or async/await (async just wraps your function in a promise, waiting for the function return, before resolving).

Thread Thread
 
gottz profile image
Jan-Stefan Janetzky • Edited

lol.. this whole thread is bogus..

first of all: Browsers do have multi threaded Javascript.. it is called workers!
node.js had proc forks at first but also moved to workers AFTER Browsers did.
some history there for ye..

secondly: promises (which async / await are) are just a flow abstraction to remove callback hell.
it is just a convenience feature.. syntax sugar...

if you really want true concurrency, use workers or wasm.

Thread Thread
 
brense profile image
Rense Bakker

Yes... But he didn't say concurrency or parallel execution, he said async is not asynchronous, which is still BS.

 
ipwright83 profile image
Ian Wright

Don't take it as we're arguing :) We're trying to understand each other and educate each other if we're incorrect. It's all constructive (at least it seems that way to me, and that's how I'm trying to pitch things).

Collapse
 
yw662 profile image
yw662 • Edited

@brense For promises, the execution function will run immediately within the current calling stack.

The promise itself won't run its fulfill callbacks in the same calling stack where it is created even if it is already fulfilled, or fulfilled directly by the executor itself, which is required by the standards. However, that does not mean it won't run the executor in the creation calling stack. It is also required by the standards that the promise runtime should not be lazy or defer the executor.

So, if it is v => new Promise(cb => cb(console.log(v))), it is sync. Console.log will run in the calling stack of the caller.

However, v => Promise.resolve().then(() => console.log(v)) is another story.

So what about async v => console.log(v) ? It is deterministic for sure, which is required by the standards. Why not try it first before you say it ?

Thread Thread
 
brense profile image
Rense Bakker

Not sure what you are replying to specifically. The code examples I gave work as expected. I was merely commenting on the incorrect assumption someone was making that async does not make javascript code asynchronous. Since then we have established they meant to say "concurrent" instead of "asynchronous", which are different things. So if there was a significant performance impact from console.log (which there isnt), using async/promises wont help.

Thread Thread
 
yw662 profile image
yw662 • Edited

@brense:
I mean @lulebe is correct technically. The async mark won't magically make a function asynchronous by itself because the promise executor is not deferred. If you mark a sync function as async, it will return a promise so it is thenable, but the execution is not asynchronous/deferred. The promise is fulfilled immediately in the same call stack before all the code lines below the invocation whether it is awaited or not.
It is the fulfillment callbacks to be deferred, but not the executor. To defer the invocation of a sync function (or a promise executor), even if it is marked as async, you need to Promise.resolve().then().

Thread Thread
 
brense profile image
Rense Bakker

No, I know what they meant to say now. They meant to say that async doesnt make code execute in parallel. They're correct about that. The whole discussion that followed, about whether promises/aync will actually allow for asynchronous execution, was pretty much a waste of everyone's time. Obviously it does.

Thread Thread
 
yw662 profile image
yw662

No I am saying nothing about being parallel. I am saying execution order.

const f1 = () => console.log(1)
const f2 = () => console.log(2)
const f3 = async() => f1()

(()=> {
  f3()
  f2()
})()
Enter fullscreen mode Exit fullscreen mode

The invocation of f3 is not awaited. However f1 runs before f2.

Thread Thread
 
brense profile image
Rense Bakker

Yes, I'm aware of that, that was never the question...

Collapse
 
yw662 profile image
yw662

But you are not making console.log async by doing this. Or maybe you can call a setTimeout to make it really happen after everything.

Thread Thread
 
adam_cyclones profile image
Adam Crockett ๐ŸŒ€ • Edited

Please forgive the bold text but many have missed even when I clarified this I want to be clear to future readers!

I said async to refer to the concept not async/await I meant what you said, I truly asynchronous function in an asynchronous context

Thread Thread
 
lulebe profile image
Leander Berg

Yeah I think saying "async" make me think you mean async/await which is just a fancy syntax for promises, which in turn are really just fancy callbacks, which don't create or use a second thread, but can be used by things like IO which uses a thread pool internally.
Of course promises thereby don't change execution order because how would they without a second thread or randomly reordering your code?

And of course none of us know whether we each have deep knowledge of that, so I just wanted to tell someone looking at this thinking "oh so I can wrap slow stuff in async functions to keep my app snappy" that it doesn't work this way. Sorry for the intense discussion that followed.

Collapse
 
mehyam profile image
MehYam

Hard disagree.

Most logging is synchronous and fast, and you want it to be synchronous for accurate sequencing of instrumentation.

And there's absolutely no harm in mixing async and sync in any language or runtime, you literally can't do anything interactive without it.

Collapse
 
akashkava profile image
Akash Kava • Edited

Because console in chrome is DOM and every line is a new element, so console.log is roughly equivalent to

let line = document.createElement("div");
for(let item of args) {  
   if (item !== null && typeof item === "object") {
       let segment = document.createElement("span");
       // little carat to open and show element
       segment.class = "drop-down"
       // some sort of expanding object children
       segment.addEventListener("click",
          () => createChildren(item)   });
          // also create some child elements to display few properties... 
          // change class if its an array etc...
          ...
          ...
       continue;
   }
   line.appendChild(document.createTextNode(item.toString()));
}
consoleElement.appendChild(line);
line.scrollIntoView();
Enter fullscreen mode Exit fullscreen mode
Collapse
 
dechamp profile image
DeChamp

Damn sure enough, it's pretty slow.

10000 rows.

with console
422.90000000596046
410.90000000596046
437.30000001192093

without
0.30000001192092896
0.4000000059604645
0.10000002384185791

Collapse
 
js2me profile image
Sergey S. Volkov

These results was created without opened dev tools tab ?

Collapse
 
adam_cyclones profile image
Adam Crockett ๐ŸŒ€

thats an interesting question, but if a log is logged in the forrest and nobody is around to see it :) I honestly dont know.

Collapse
 
alvaromontoro profile image
Alvaro Montoro

Makes sense. I/O operations are slow (even if it's just output on the screen.)

Collapse
 
dimensioncloud profile image
DimensionCloud • Edited

Try to reduce the amount of data that is stored in the console.log, also use session store instead of file.
with the definition set as needed here

EXAMPLE:
// Save element position
app.post('/position', (req, res) => {
const positionData = req.body;
const elementId = positionData.elementId;
const sessionData = req.session;

// Update the session data with the new position data for the element
sessionData[elementId] = positionData;

// Return a success status code
res.sendStatus(200);
});

Collapse
 
adam_cyclones profile image
Adam Crockett ๐ŸŒ€ • Edited

server.log? im refering to JavaScript console.log in both browser and backend environments, particularly in memory and chromium

Collapse
 
dimensioncloud profile image
DimensionCloud

U can also use session store with redis.

Thread Thread
 
dimensioncloud profile image
DimensionCloud

look on my files how I solved faster response.

Collapse
 
jamesvanderpump profile image
James Vanderpump

Displaying a console.log in a terminal is super slow period.

Collapse
 
dechamp profile image
DeChamp

now i'm curious. What numbers did you see?

Collapse
 
rysilva01 profile image
RYSILVA01

How did you get it ?
You got me curious. Show us plz

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
loyal_robin profile image
Robin

This is generated by chatgpt, isn't it?

Collapse
 
adam_cyclones profile image
Adam Crockett ๐ŸŒ€

No ๐Ÿ™ I just write on my phone, what makes you say that?

Collapse
 
adam_cyclones profile image
Adam Crockett ๐ŸŒ€

Oh did you mean the comment sorry I was out of context

Collapse
 
ciach0 profile image
__Ciach0

This is intentional, the Node.js docs say:

A note on process I/O#
process.stdout and process.stderr differ from other Node.js streams in important ways:

They are used internally by console.log() and console.error(), respectively.
Writes may be synchronous depending on what the stream is connected to and whether the system is Windows or POSIX:
Files: synchronous on Windows and POSIX
TTYs (Terminals): asynchronous on Windows, synchronous on POSIX
Pipes (and sockets): synchronous on Windows, asynchronous on POSIX
These behaviors are partly for historical reasons, as changing them would create backward incompatibility, but they are also expected by some users.

Synchronous writes avoid problems such as output written with console.log() or console.error() being unexpectedly interleaved, or not written at all if process.exit() is called before an asynchronous write completes. See process.exit() for more information.

Collapse
 
ipwright83 profile image
Ian Wright

Might be good to show some examples... stackoverflow.com/a/26754011/21061 gives a nice breakdown with evidence...

Collapse
 
adam_cyclones profile image
Adam Crockett ๐ŸŒ€

Thanks youโ€™ve all been helpful providing evidence and tests I didnโ€™t expect this post to blow up so much ๐Ÿ˜ฎ I see the point about evidence and agree but I just wrote this while making breakfastโ€ฆ.

Collapse
 
mrh0200 profile image
MR.H • Edited
Collapse
 
privateger profile image
PrivateGER

You're causing a write operation, which is inherently blocking. Buffer your output or don't have any at all when it's performance critical.

Collapse
 
kakol20 profile image
Adrian Aquino-Neary

It's like cout in C++. You shouldn't really use both cout and console.log if you're looking for performance in the console.