我试了很长时间才弄清楚事件和事件循环是如何工作的。我在网上阅读了很多关于事件注册和事件循环的文章,但我仍然无法想象它是如何工作的。
我正在阅读Prgmatic Bookshelft关于事件队列的Async JavaScript一书,你可以在书中看到一篇文章。
> 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.
在这篇文章之后,我对javascript中的事件和异步有了一点想象力。然后我自己尝试以下代码:
setTimeout(function(){alert("Hello")},0);
for (var i = 0; i <= 100000; i++) {
console.log('I am loop');
}
我已将时间设为0,因为我想确认这句话
the code after the setTimeout call runs and so on..
和
After then it will start the event loop and...
直到这里,一切都很好javascript它的工作原理。然后我继续阅读Async JavaScript书籍,并阅读了以下内容:
输入事件的工作方式相同:当用户点击DOM元素时 附加了一个点击处理程序,一个点击事件排队。但是处理程序 在所有当前运行的代码完成之前不会执行。
第一句话对我来说有点混乱。例如:
//Some codes
#("element").click(function(e){
//Do something
});
//Some codes
我在这里不明白的是,什么时候编译器会在事件队列中保存click事件?它会在注册后保存在队列中(在此代码中)或者当我点击元素时?
在节点中,我尝试使用此代码,以了解事件的工作原理。请考虑以下代码。
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');
我期待的是:
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
但我得到的是:
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
在这个输出之后,它打破了关于事件(异步)执行和事件循环的所有想象,我之前阅读过书中的文章和文章。请考虑书中的这句话:
setTimeout调用之后的代码运行,因此,直到没有更多的代码 剩下。之后它将启动事件循环并检测哪个事件 被解雇,它会调用处理程序。
但为什么上面与EventEmitter的代码相反?我认为事件循环将在结束时执行(在完成其他代码之后)。
我在互联网上读过关于数据库(例如mongoose)查询与节点是异步的。我不知道异步数据库查询是如何确定的,但我的成像是这样的:
请解释一下,javascript中的事件是如何运作的?
答案 0 :(得分:1)
setTimeout
与EventEmitter
略有不同,因为您获得了这些结果。首先,我会请你先运行这些例子。
将其保存在async.html中并在浏览器中运行。检查控制台以查看结果。
<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>
输出
Inside
I am loop
I am loop
I am loop
I am loop
I am loop
Hello
现在将其保存在async.js中并在node.js中运行
setTimeout(function(){console.log("Hello")},0);
for (var i = 0; i < 5; i++) {
console.log('I am loop');
}
输出
I am loop
I am loop
I am loop
I am loop
I am loop
Hello
您会发现setTimeout
的工作方式与EventEmitter
略有不同。 EventEmitter立即执行处理程序,而setTimeout尝试立即执行它。直到下一个滴答时才执行操作。阅读它here。
不要将setTimeout与EventEmitter混合使用。
您的示例并未充分展示异步。您只是在事件处理程序中运行循环。这是一个更清晰的例子:
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);
});
我想指出,我只使用setTimeout
和事件来感受工作到达和处理延迟的延迟,这与他们在问题中的同义用法不同。 emitclosure
只是循环变量的闭包,因此它们的范围是安全的。