node.js + MongoDB + AngularJS - 4 事件、监听器、定时器、回调
来源:互联网 发布:mac display color 编辑:程序博客网 时间:2024/04/30 00:22
node.js通过其强大的事件驱动模型提供了可扩展性和性能。了解事件模型至关重要,因为它可能迫使你改变设计应用程序的思维。
1. 了解Node.js事件模型
Node.js应用程序在一个单线程的事件驱动模型中运行。
1.1 比较事件回调和线程模型
- 传统的线程网络模型
请求进入一个web服务器,并被分配给一个可用的线程。对于该请求的处理工作继续在该线程上进行,直到请求完成并发出响应。
- Node.js事件模型的工作原理
Node.js不是在各个线程为每个请求执行所有的工作,反之,它把工作添加到一个事件队列中,然后有一个单独的线程运行一个事件循环把这个工作提取出来。
1.2 在Node.js中阻塞I/0
阻塞I/O的例子:
- 读取文件
- 查询数据库
- 请求套接字
- 访问远程服务
Node.js使用事件回调来避免对阻塞I/O的等待。因此,执行阻塞I/O的任何请求都在后台的不同的线程中执行。Node.js在后台实现线程池。当该块的I/O从时间队列中检测一个事件,Node.js从线程池中获取一个线程,并在那里执行功能,而不是主事件循环线程执行功能。这可以防止阻塞I/O阻碍事件队列中的其余事件。
2. 将工作添加到事件队列
在Node.js应用程序中,你可以使用下列方法之一传递回调函数来在事件队列中调度工作:
- 对阻塞I/O库调用之一做出调用
- 对内置的事件
- 创建自己的事件发射器并对它们添加自定义的监听器
- 使用process.nextTick选项来调度在事件循环的下一次循环中被提取出的工作
- 使用定时器来调度在特定时间数量或每隔一段时间后要做的工作
2.1 实现定时器
- 用超时时间来延迟工作
超时定时器用于将工作延迟一个特定时间数量。当时间到了,回调函数执行,而定时器消失。对于只需要执行一次的工作,你应该使用超时时间。
setTimeout( callback, delayMilliSeconds, [ args ] ) ;setTimeout( myFunc, 1000 ) ;
setTimeout() 函数返回一个定时器对象的ID,你可以在delayMilliSeconds到期前的任何时刻把此ID传递给clearTimeout( timeoutID )来取消超时时间函数。
myTimeout = setTimeout( myFunc, 1000000 ) ;clearTimeout( myTimeout ) ;
- 用时间间隔执行定期工作
时间间隔定时器用于按定期的延迟时间间隔执行工作。当延迟时间结束时,回调函数被执行,然后再次重新调度为该延迟时间。对于必须定期进行的工作,你可以使用时间间隔。
myInterval = setInterval( myFunc, 1000 ) ;clearInterval( myInterval ) ;
- 使用即时计时器立即执行工作
即时计时器用来在I/O时间的回调函数开始执行后,但任何超时时间或时间间隔事件被执行之前,立刻执行工作。它们允许你把工作调度为在事件队列中的当前事件完成之后执行。你应该使用即时定时器为其他回调产生长期运行的执行段,以方式I/O饥饿。
myImmediate = setImmediate( myFunc ) ;clearImmediate( myImmediate ) ;
- 从事件循环中取消定时器引用
当定时器事件回调是留在事件队列中的仅有事件时,通常你不会希望它们继续被调度。Node.js提供了一个非常有用的工具来处理这种情况。这个工具是在setInterval和setTimeout返回的对象中可用的unref()函数,它让你能够在这些事情是队列中仅有的事件时,通知事件循环不要继续。
myInterval = setInterval( myFunc ) ;myInterval.unref() ;
可以重新引用:
myInterval.ref() ;
2.2 使用nextTick来调度工作
在事件队列上调度工作的一个非常有用的方法是使用process.nextTick( callback )函数。此函数调度要在事件循环的下一次循环中运行的工作。不想setImmediate()方法,nextTick()在I/O事件被触发之前执行。这可能会导致I/O事件的饥饿,所以Node.js通过默认值1000的process.maxTickDepth来限制事件队列的每次循环可执行的nextTick()事件的数目。
2.3 实现事件发射器和监听器
创建自己的自定义事件,以及实现当一个事件被发出时执行的监听器回调。
- 将自定义事件添加到Javascript对象
事件使用一个EventEmitter对象发出。这个对象包含在events模块中。emit( eventName, [ args ] ) 函数触发eventName事件,包含所提供的任何参数。
var events = require( 'events' ) ;var emitter = new events.EventEmitter() ;emitter.emit( 'simpleEvent' ) ;
直接把事件添加到你的Javascript对象,需要通过在对象实例中调用events.EventEmitter.call( this ) 来继承EventEmitter功能。你还需要把events.EventEmitter.prototype添加到对象的原型中。
function MyObj() { Events.EventEmitter.call( this ) ;}MyObj.prototype.__proto__ = events.EventEmitter.prototype ;var myObj = new MyObj() ;myObj.emit( 'someEvent' ) ;
把事件监听器添加到对象
.addListener( eventName, callback ) : 将回调函数附加到对象的监听器中。每当eventName事件被触发时,回调函数就被重置在事件队列中执行。
- .on( eventName, callback ) : 同.addListener()
.once( eventName, callback ) : 只有eventName事件第一次被触发时,回调函数才被放置在事件队列中执行。
在对象中删除监听器
.listeners( eventName ) : 返回一个连接到eventName事件的监听器函数的数组
- .setMaxListerers( n ): 如果多余n的监听器都加入到EventEmitter对象,就触发警报。默认值是10
- .removeListener( eventName, callback ) : 将callback函数从EventEmitter对象的eventName事件中删除
3. 实现回调
- 将参数传递给回调函数
- 在循环内处理回调函数参数
- 以及嵌套回调
3.1 向回调函数传递额外的参数
大部分回调函数都有传递给它们的自动参数,如错误或结果缓冲区。使用回调时,常见的一个问题是如何从调用函数给他们传递额外的参数。做到这一点的方法是在一个匿名函数中实现该参数,然后用来自匿名函数的参数调用回调函数。
var events = require( 'events' ) ;function CarShow() { events.EventEmitter.call( this ) ; this.seeCar = function( make ) { this.emit( 'sawCar', make ) ; }}CarShow.prototype.__proto__ = events.EventEmitter.prototype ;var show = new CarShow() ;function logCar( make ) { console.log( 'Saw a ' + make ) ;}function logColorCar( make, color ) { console.log( 'Saw a %s %s', color, make ) ;}show.on( 'sawCar', logCar ) ;show.on( 'sawCar', function( make ) { var colors = [ 'red', 'blue', 'black' ] ; var color = colors[ Math.floor( Math.random() * 3 ) ] ; logColorCar( make, color ) ;} ) ;show.seeCar( 'Ferrari' ) ;show.seeCar( 'Porsche' ) ;show.seeCar( 'Bugatti' ) ;show.seeCar( 'Lamborghini' ) ;show.seeCar( 'Astom Martin' ) ;
3.2 在回调中实现闭包
- 闭包:变量被绑定到一个函数的作用域,但不绑定到他的父函数的作用域。
当你执行一个异步回掉时,父函数的作用域可能改变,如果某个回调函数需要访问父函数的作用域的变量,就需要提供闭包,使这些值在回调函数从事件队列被提取出时,可以得到。
function logCar( logMsg, callback ) { process.nextTick( function() { callback( logMsg ) ; } ) ;}var cars = [ 'Ferrari', 'Porsche', 'Bugatti' ] ;for( var idx in cars ) { var message = 'Saw a ' + cars[ idx ] ; logCar( message, function() { console.log( 'Normal Callback: ' + message ) ; } ) ;}for( var idx in cars ) { var message = 'Saw a ' + cars[ idx ] ; ( function( msg ){ logCar( msg, function() { console.log( 'Closure Callback: ' + msg ) ; } ); } )( message ) ;}
3.3 链式回调
使用异步函数时,如果两个函数都在事件队列上,则你无法保证它们的运行顺序。解决这一问题的最佳方式是让来自异步函数的回调再次调用该函数,知道没有更多的工作要做,以执行链式回调。
- node.js + MongoDB + AngularJS - 4 事件、监听器、定时器、回调
- node.js事件监听器
- Node.js EventEmmitter事件监听器
- AngularJS+Satellizer+Node.js+MongoDB
- Node.js + MongoDB + AngularJS - 1
- node.js实现事件发射器和监听器
- Node.js 事件发射器和监听器
- Node.js+MongoDB+AngularJS Web开发
- Node.js + MongoDB + AngularJS - 2 Javascript基础
- 学习Node.js+MongoDB+AngularJS(1)
- node.js + MongoDB + AngularJS - 3 开始使用Node.js
- Node.js + MongoDB + AngularJS - 6 访问文件系统-1
- Node.js + MongoDB + AngularJS - 6 访问文件系统-2
- Node.js + MongoDB + AngularJS - 5 在Node.js中处理数据I0-1
- Node.js + MongoDB + AngularJS - 5 在Node.js中处理数据I0-2
- node.js(一)包管理、缓冲区、事件驱动、定时器
- Node.js 定时器
- Node.js 定时器
- Linux Shell脚本编程--变量$#,$@,$*,$?,$0,$1,$2的含义解释
- Linxu操作笔记
- 如何不让键盘挡住UITextField控件
- Python爬虫入门笔记:一个简单的爬虫架构
- VS中的路径宏 vc++中OutDir、ProjectDir、SolutionDir各种路径
- node.js + MongoDB + AngularJS - 4 事件、监听器、定时器、回调
- 运用腾讯云实现QQ语音通话
- HDU 4497 GCD and LCM (素数筛选+算术基本定理)
- 将C语言的声明翻译成通俗的语言
- Java 8 新特性:接口的静态方法和默认方法 ——诺诺"涂鸦"记忆
- C/C++自动生成makefile工具 supermake
- javascript常用数组算法总结
- maven自定义(修改)编译后输出的war或jar文件名
- HDOJ(HDU) 1859 最小长方形(水题、、)