Description
It's surprising how deep this whole is
Problem 1: one log -> one msg -> one update
This first problem I fixed was one call to console.log would generate one message send the main page
which would update the array of messages and trigger a redraw by react.
This had the issue that if you log a bunch of strings as in for (let i = 0; i < 10000; ++i) { console.log(i); }
each of those 10k strings sent a message and each message trigger a re-draw which resulted in it taking minutes to actually display those messages.
That was fixed by batching the messages and throttling sending them.
Problem 2: no yield = no processing setTimeout
A new issue remained, if you issue 10k calls to log like the example above the throttling above still prevents any messages from getting displayed until JavaScript yields because the browser is single threaded so the setTimeout
for used for throttling can't actually get processed until JavaScript yields. In other words you have this
for (let i = 0; i < 10000; ++i) {
doSomethingThatTakesTime()
console.log(i);
}
Assume it takes 10 seconds for that loop to end, nothing gets displayed in the log because the throttling of messages is based on setTimeout
and JavaScript will not process the more events until the currently running event exits
I tried to fix that by adding a 2nd throttle which uses performance.now
to see if some time as passed and if so to flush the queued messages
This seems like it would in Chrome AFAIK because Chrome will run the iframes from another domain in another process. Unfortunately, the host for the runner is in the same domain so it can't process messages until it's iframe yields. In other words this is the current structure
[jsgist.org]
[jsgistrunner.devcomments.org/runner.html]
[jsgistrunner.devcomments.org/user-jsgist.html]
Because user-jsgist.html
is on the same domain as runner.html
they run in the same process so runner.html
will not process any messages until user-jsgist.html
yeilds
I could try to put user-jsgist.html
in it's own domain but that would leave problem #3
Problem #3, no calls to console.log = no processing
Solution #2 attempted to let the code send messages even if the code does not yield by using performance.now
to check if our time limit has passed and if so, sending the queued messages. This though is dependent on calling console.log
. If you did this
console.log('hello world');
processThatTakes10Seconds();
You'd not see the message until 10 seconds have passed because there are no more calls to console.log
for it to check
AFAIK the only real solution is to use a worker, send the messages to the worker, the worker won't sleep so it can do the throttling. I'm not sure that's a good solution or not. For it to work the user's process would have to send one message at a time (no queuing). The queuing would happen in the worker.
I have no yet implemented this solution