学习nodejs中的事件和循环。

与此相关的建议:nodejs教程
对于熟悉javascript的朋友,应该会使用一些事件,例如鼠标移动、鼠标点击、键盘输入等。通过监听javascript中的这些事件,我们可以触发相应的处理。
事件存在于相同的nodejs中,并且有一个专门的events模块用于特殊处理。
在nodejs中,事件和事件循环是构建异步IO的重要概念。
现在我们来做个详细的介绍。
活动。
nodejs提供了用于事件的专用模块:lib/events.js。
记住,我们说过要用nodejs构建web服务器。
配置服务器=http.createServer((req,res)=>{
res.statuscode=200。
res.setHeader(“文本/序言类型”)
end('welcometowww.flydean.com)
')
})
其中,请求事件由每个请求触发。
Nodejs的核心API是基于异步事件驱动的体系结构,因此nodejs中存在大量事件。
例如:net.Server每当有新连接时都会触发事件,fs.ReadStream则在文件打开时触发,而stream则在数据可读时触发。
看看如何为nodejs构建事件吧:
constEventEmitter=require(中心)
consteventEmitter=新的事件EventEmitter()
vents的常用方法有两种,on和emit。
on用于监听事件,emit用于触发该事件。
eventEmitter.on('fire')=>{
Console.log(点火)
})
Emitter.emit('fire')
emit也可以使用参数,我们来看看下一个:
eventEmitter.on('fire',who=>{
console.log(${who}) }) eventEmitter.emit('fire','美帝') 看一下另外两个参数: eventEmitter.on('fire'(who,when)=>{ (射击${who}${when})console.log }) eventEmitter.emit('fire','川的建国','now') 缺省情况下,EventEmitter按注册顺序同步调用所有监听器。这确保了事件的正确排序,并且有助于避免竞争状态和逻辑错误。 如果需要异步执行,您可以使用setImmediate()或process.nextTick()将其切换为异步执行模式。 eventEmitter.on('fire'(who,when)=>{ setImmediate()=>{ console.log(射击${who}${when});
});
})
eventEmitter.emit('fire','川的建国','now')
除了这些,events还支持其他一些方法:
once():添加一个单独的监听器。
removeListener()/off():将事件监听器从事件中删除。
removeAllListeners():为事件删除所有监听器。
活动循环。
据我们所知,nodejs的代码运行在单线程环境中,每次只能处理一件事情。
这种处理方式避免了多线程环境下的数据同步问题,大大提高了处理效率。
称为事件循环,是指处理器在一个程序周期内,处理完一个周期的事件后,将进入下一个周期,处理下一个周期的事情,这样,一个周期的事件将进入下一个周期。
阻止事件循环。
在事件处理期间,如果某个事件的处理被阻塞,那么其他事件的执行将受到影响,因此可以看到JS中几乎所有的IO都是非阻塞的。这就是javascript中回调函数如此之多的原因。
活动周期举例
下面看看一个简单的循环事件示例:
2=()=>console.log('action2')
3=()=>console.log('action3')
配置1=()=>{
Console.log('action1')
动作2()
动作3()
}
操作1()
上述代码输出:
动作1。
动作2。
动作3。
栈和消息队列。
在上面的示例中,我们知道函数之间的调用是通过栈实现的,并且我们的调用顺序也是通过栈实现的。
但是,并非函数中的所有方法都会进入栈,而其他方法则会进入消息队列。
下面还有另一个例子:
2=()=>console.log('action2')
3=()=>console.log('action3')
配置1=()=>{
Console.log('action1')
Setimeout(action2,0)
操作3()
}
操作1()
上述代码运行结果:
动作1。
动作3。
动作2。
情况有所不同。由于settimeout触发了计时器,当计时器过期时,回调函数将被放在消息队列中等待处理,而不是放在栈中。
当栈中没有任何数据时,事件循环将优先处理栈中的事件,并将转至消耗消息队列中的事件。
尽管上例中setTimeout的timeout时间为0,但在完成action3之前仍需等待。
请注意,setTimeout中的timeout不在当前线程中等待,浏览器或其他JS执行环境将调用该线程。
任务队列和代理列表。
Promise在ES6中引入了作业队列的概念,使用作业队列将尽可能快地执行异步功能的结果,而不是把它放在调用堆栈的末尾。
举例来说:
2=()=>console.log('action2')
3=()=>console.log('action3')
配置1=()=>{
Console.log('action1')
Setimeout(action2,0)
新项目计划((恢复,恢复)=>。
resolve(“应该在动作3之后,动作2之前”)
(a).then(resolve=>console.log)
动作3()
}
操作1()
产出:
动作1。
动作3。
应在动作3之后,动作2之前。
动作2。
原因在于resolve的Promise在当前函数结束前将在该函数之后立即执行。
也就是,首先执行栈,然后是作业队列,最后是消息队列。
(c)process.nextTick
nextTick(()=>{
log('iamthenexttick');
})
因此,nextTick必须快于消息队列的setTimeout。
SetImmediate()
为了尽快执行代码,nodejs提供了setImmediate方法。
setImmediate()=>{
log('Iamimmediate!');
})
在setImmediate中的函数将在下一次事件循环中执行。
setImmediate()和setTimeout(()=>{},0)具有基本相似的功能。他们都将在事件循环的下一次迭代中运行。
setInterval()
如果您希望定时执行某些回调函数,您需要使用setInterval。
SetInterval(()=>{
console.log(每2秒执行一次);
},2000)
使用clearInterval,可以清除以上定时任务:
Constid=setInterval()=>{
console.log(每2秒执行一次);
},2000)
clearInterval(ID)
请注意,setInterval是每隔n毫秒启动一个函数,无论它完成与否。
当一个函数执行得太久,导致下一个函数同时执行时,如何来解决这个问题?
可考虑在回调函数中再次调用setTimeout,从而形成一个递归的setTimeout调用:
配置=()=>{{
console.log('完成后,隔天执行2次!');
Setimeout(MyFunction,2000年)
}
Setimeout(MyFunction,2000年)

上一篇:unity|火焰和烟效果(粒子系统)


下一篇:黑菜菌的JAVA学习笔记