Question

I tried a long time to figure out, how event and event loop works. I read so many article in internet and books about event registration and event loop, but I still can not imagine how it works.

I am reading the book Async JavaScript from Prgmatic Bookshelft about event queue, you can read in the book an article.

When we call setTimeout, a timeout event is queued. Then execution continues, the code after the setTimeout call runs and so on, until no code more left. After then it will start the event loop and detect, which event get fired and it will call the handler.

After this article, I have got a bit imagination about event and async in Javascript. Then I tried by myself the following code:

setTimeout(function(){alert("Hello")},0);

for (var i = 0; i <= 100000; i++) {
    console.log('I am loop');
}

I have set the time 0, because I want to have confirmation about this sentence:

the code after the setTimeout call runs and so on..

and

After then it will start the event loop and...

until here, everything is fine how event in Javascript; it works. Then I keep continue reading Async JavaScript book, and had read the following:

Input events work the same way: when a user clicks a DOM element with a click handler attached, a click event is queued. But the handler won't be executed until all currently running code had finished.

The first sentence sounds for me a bit confused. For example:

//Some codes
#("element").click(function(e){
    //Do something
});
//Some codes

What I don't understand here is, when the compiler will saved a click event in the event queue? Will it be saved in the queue after registration (after this code) or when I had clicked the element?

In node I tried this code, to figure out how event works. Consider the following code:

var events = require("events");
var event = new events.EventEmitter();

event.on('ev1', function () {
    console.log('Into ev1');

});

event.emit('ev1');
for (var i = 0; i <= 5; i++) {
    console.log('I am in the loop');
}

console.log('I am finish with loop');

What I am expected here is:

I am in the loop
I am in the loop
I am in the loop
I am in the loop
I am in the loop
I am in the loop
I am finish with loop
Into ev1

but what I got it is:

Into ev1
I am in the loop
I am in the loop
I am in the loop
I am in the loop
I am in the loop
I am in the loop
I am finish with loop

After this output, it breaks all my imagination about event (async) execution and event loop that I had read in the book and article in the net before. Consider this sentence in the book:

the code after the setTimeout call runs and so, until no code more left. After then it will start the event loop and detect, which event get fired and it will call the handler.

But why the code above with the EventEmitter works opposite? I thought the event loop will be execute at the end (after other codes be done).

I had read in internet about database (for example mongoose) query with node is async. I don't know how async database query definitively works, but I am imagining like this:

Database request and response

Please explain me, how events in Javascript really work?

Was it helpful?

Solution

setTimeout is a bit apart from EventEmitter, due to which you are getting these results. First of all I would ask you to run these examples first.

Save this in async.html and run it in your browser. Check the console to see the results.

<div id="element">
</div>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script>
setTimeout(function(){console.log("Hello")},0);
$("#element").click(function(e){
    console.log("Inside");
});
$("#element").click();
for (var i = 0; i < 5; i++) {
    console.log('I am loop');
}
</script>

Output

Inside
I am loop
I am loop
I am loop
I am loop
I am loop
Hello

Now save this in async.js and run this in node.js

setTimeout(function(){console.log("Hello")},0);

for (var i = 0; i < 5; i++) {
    console.log('I am loop');
}

Output

I am loop
I am loop
I am loop
I am loop
I am loop
Hello

You will find that setTimeout works a little different than EventEmitter. An EventEmitter executes the handler immediately whereas setTimeout attempts to execute it immediately. The actions are not performed until the next tick. Read about it here.

Do not mix setTimeout with EventEmitter.

Edit

Your example does not demonstrate asynchrony quite well. You are simply running a loop inside the event handler. Here is a more clear example :

var events = require("events");
var event = new events.EventEmitter();

event.on("work", function (i,cb) {
    console.log('Started '+i );
    setTimeout(function(){event.emit("done",i,cb);},Math.random()*1000);
});

event.on("done", function (i,cb) {
    cb(i);
});

var async = function (cb) {
    for (var i = 0; i <= 100; i++) {
        emitclosure(i,cb);
    }
}

function emitclosure(i,cb){
        setTimeout(function(){event.emit("work",i,cb)},Math.random()*1000);
}

async(function (i) {
    console.log("I have done "+i);
});

I would point out that I use setTimeout along with events only to give a feel of delay of arrival of work and processing delay, unlike their synonymous use in the question. emitclosure is just a closure for loop variables, so that their scope is safe.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top