Reputation: 2616
Is the concept of event loop general or specific to languages? I am looking for detailed explanations with examples to clearly understand the following:
1. how it works?
Update:
There's no dearth of answers to this but I'm looking for an easy to understand definition with examples.
Consider the following code:
var list = readHugeList();
var nextListItem = function() {
var item = list.pop();
if (item) {
// process the list item...
setTimeout( nextListItem, 0);
}
};
Is it correct to assume setTimeout() here uses the event loop to prevent stackoverflow? I read an explanation for this code that:
The stack overflow is eliminated because the event loop handles the recursion, not the call stack.
The full explanation given for the setTimeout() in the code above is as follows:
The stack overflow is eliminated because the event loop handles the recursion, not the call stack. When nextListItem runs, if item is not null, the timeout function (nextListItem) is pushed to the event queue and the function exits, thereby leaving the call stack clear. When the event queue runs its timed-out event, the next item is processed and a timer is set to again invoke nextListItem. Accordingly, the method is processed from start to finish without a direct recursive call, so the call stack remains clear, regardless of the number of iterations.
The contradiction in explanations, aforementioned and in the answers here, is making it all the more difficult to understand.
Upvotes: 1
Views: 685
Reputation: 1075337
Is the concept of event loop general or specific to languages?
At its highest level, general. But different environments will implement the details so differently that really you need environment-specific information to know what's going on.
how it works?
All the gory details are in the specification, chiefly in the section called Jobs and Job Queues.
There are a couple of keys aspects:
There is a queue of jobs (the JavaScript spec's term) or "tasks" (as the HTML spec calls them) waiting to be run by the JavaScript engine. When the engine finishes a job, it's put to work on the next job/task in the queue, if any.
Once a job is started, it keeps running until it's done; no other jobs can interrupt it. This is called run-to-completion and is very important to the definition of how JavaScript works.
The job queue is processed in order.
So consider this code:
console.log("one");
setTimeout(function() {
console.log("two");
}, 1000);
If you run that code (via NodeJS or a browser), here's what happens (omitting some irrelevant details):
setTimeout
Now consider this code:
console.log(Date.now(), "one");
setTimeout(function first() {
console.log(Date.now(), "two");
}, 500);
setTimeout(function second() {
var end = Date.now() + 1000;
while (end > Date.now()) {
// Busy-wait (normally this is a Bad Thing™, I'm using it here
// to simulate actual work that takes significant time
}
}, 100);
As you can see, it schedules a timed callback at 500ms and then another at 100ms. But the code in the callback at 100ms will take at least 1000ms to run. What happens?
1470727293584 one
first
for 500ms in the futuresecond
for 100ms in the futuresecond
first
; since the JavaScript engine is busy with the previous job, the job sits in the queuefirst
:
second
1470727294687 two
Note that the environment did something while JavaScript was busy; it queued a job to be done.
The fact that the environment can do things while the JavaScript engine is busy is very important.
(It's worth noting that when queuing jobs, some environments may not necessarily add the job at the end of the queue; in some browsers, for instance, "the queue" is actually more than one queue with slightly different priorities...)
how/when should/can I leverage it?
It's not so much leveraging it as knowing it's there. It's also important to note that while JavaScript has run-to-completion semantics, the environment in which it's running may be doing other things at the same time, even while the JavaScript code is running.
any changes introduced in ECMAScript-6/2015 regarding event loop?
Not really, although it's defined much more completely in the spec than previously. Probably the closest thing to a change is in relation to promises: The callback you schedule with then
or catch
will always be queued as a job, it will never be run synchronously. That's the first time the JavaScript specification has defined something that happens asynchronously (ajax and timers are not part of the JavaScript spec).
Below, you've asked:
Consider this code:
var list = readHugeList(); var nextListItem = function() { var item = list.pop(); if (item) { // process the list item... setTimeout(nextListItem, 0); } };
Is it correct to assume setTimeout() here uses the event loop to prevent stackoverflow?
(I assume there's a nextListItem();
call immediately after that.)
No, but it's doing something else important. The non-setTimeout
version of that would look something like this:1
var list = readHugeList();
while (list.length) {
var item = list.pop();
// process the list item...
}
That's a simple loop, there's no potential for stack overflow.
What it's doing is working cooperatively with the event loop, avoiding having a really long-running job that would tie up the JavaScript engine, preventing it processing any other jobs (such as I/O completions, clicks, or other events). So it's breaking the work up into small jobs by processing the items one at a time, helping ensure that the overall job queue keeps getting processed. That means it takes a lot longer to process the list, but doesn't block other things while doing so.
1 It's true that the non-setTimeout
version of that code could look like this:
var list = readHugeList();
var nextListItem = function() {
var item = list.pop();
if (item) {
// process the list item...
// then recurse
nextListItem();
}
};
nextListItem();
...and in that case, there's potential for stack overflow, but it would be a very odd way to write that code.
Upvotes: 4