什么是事件,它又如何工作,react eventemitterr是个什么货

Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。
Node.js里面的许多对象都会分发事件:一个net.Server对象会在每次有新连接时分发一个事件, 一个fs.readStream对象会在文件被打开的时候发出一个事件。 所有这些产生事件的对象都是 events.EventEmitter 的实例。
EventEmitter 类
events 模块只提供了一个对象: events.EventEmitter。EventEmitter 的核心就是事件触发与事件监听器功能的封装。
你可以通过require("events");来访问该模块。
// 引入 events 模块
var events = require('events');
// 创建 eventEmitter 对象
var eventEmitter = new events.EventEmitter();
EventEmitter 对象如果在实例化时发生错误,会触发 'error' 事件。当添加新的监听器时,'newListener' 事件会触发,当监听器被移除时,'removeListener' 事件被触发。
下面我们用一个简单的例子说明 EventEmitter 的用法:
//event.js 文件
var EventEmitter = require('events').EventEmitter;
var event = new EventEmitter();
event.on('some_event', function() {
console.log('some_event 事件触发');
setTimeout(function() {
event.emit('some_event');
执行结果如下:
运行这段代码,1 秒后控制台输出了&'some_event 事件触发'。其原理是 event 对象注册了事件 some_event 的一个监听器,然后我们通过 setTimeout 在 1000 毫秒以后向 event 对象发送事件 some_event,此时会调用some_event 的监听器。
$ node event.js
some_event 事件触发
EventEmitter 的每个事件由一个事件名和若干个参数组成,事件名是一个字符串,通常表达一定的语义。对于每个事件,EventEmitter 支持 若干个事件监听器。
当事件触发时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递。
让我们以下面的例子解释这个过程:
//event.js 文件
var events = require('events');
var emitter = new events.EventEmitter();
emitter.on('someEvent', function(arg1, arg2) {
console.log('listener1', arg1, arg2);
emitter.on('someEvent', function(arg1, arg2) {
console.log('listener2', arg1, arg2);
emitter.emit('someEvent', 'arg1 参数', 'arg2 参数');
执行以上代码,运行的结果如下:
$ node event.js
listener1 arg1 参数 arg2 参数
listener2 arg1 参数 arg2 参数
以上例子中,emitter 为事件 someEvent 注册了两个事件监听器,然后触发了 someEvent 事件。
运行结果中可以看到两个事件监听器回调函数被先后调用。 这就是EventEmitter最简单的用法。
EventEmitter 提供了多个属性,如&on&和&emit。on&函数用于绑定事件函数,emit&属性用于触发一个事件。接下来我们来具体看下 EventEmitter 的属性介绍。
序号方法 & 描述
addListener(event, listener)为指定事件添加一个监听器到监听器数组的尾部。
on(event, listener)为指定事件注册一个监听器,接受一个字符串 event 和一个回调函数。
server.on('connection', function (stream) {
console.log('someone connected!');
once(event, listener)为指定事件注册一个单次监听器,即 监听器最多只会触发一次,触发后立刻解除该监听器。
server.once('connection', function (stream) {
console.log('Ah, we have our first user!');
removeListener(event, listener)移除指定事件的某个监听器,监听器 必须是该事件已经注册过的监听器。
var callback = function(stream) {
console.log('someone connected!');
server.on('connection', callback);
server.removeListener('connection', callback);
removeAllListeners([event])移除所有事件的所有监听器, 如果指定事件,则移除指定事件的所有监听器。
setMaxListeners(n)默认情况下, EventEmitters 如果你添加的监听器超过 10 个就会输出警告信息。 setMaxListeners 函数用于提高监听器的默认限制的数量。
listeners(event)返回指定事件的监听器数组。
emit(event, [arg1], [arg2], [...])按参数的顺序执行每个监听器,如果事件有注册监听返回 true,否则返回 false。
序号方法 & 描述
listenerCount(emitter, event)返回指定事件的监听器数量。
序号事件 & 描述
newListener
event&- 字符串,事件名称
listener&- 处理事件函数
该事件在添加新监听器时被触发。
removeListener
event&- 字符串,事件名称
listener&- 处理事件函数
从指定监听器数组中删除一个监听器。需要注意的是,此操作将会改变处于被删监听器之后的那些监听器的索引。
以下实例通过 connection(连接)事件演示了 EventEmitter 类的应用。
创建 main.js 文件,代码如下:
var events = require('events');
var eventEmitter = new events.EventEmitter();
// 监听器 #1
var listener1 = function listener1() {
console.log('监听器 listener1 执行。');
// 监听器 #2
var listener2 = function listener2() {
console.log('监听器 listener2 执行。');
// 绑定 connection 事件,处理函数为 listener1
eventEmitter.addListener('connection', listener1);
// 绑定 connection 事件,处理函数为 listener2
eventEmitter.on('connection', listener2);
var eventListeners = require('events').EventEmitter.listenerCount(eventEmitter,'connection');
console.log(eventListeners + " 个监听器监听连接事件。");
// 处理 connection 事件
eventEmitter.emit('connection');
// 移除监绑定的 listener1 函数
eventEmitter.removeListener('connection', listener1);
console.log("listener1 不再受监听。");
// 触发连接事件
eventEmitter.emit('connection');
eventListeners = require('events').EventEmitter.listenerCount(eventEmitter,'connection');
console.log(eventListeners + " 个监听器监听连接事件。");
console.log("程序执行完毕。");
以上代码,执行结果如下所示:
$ node main.js
2 个监听器监听连接事件。
监听器 listener1 执行。
监听器 listener2 执行。
listener1 不再受监听。
监听器 listener2 执行。
1 个监听器监听连接事件。
程序执行完毕。
error 事件
EventEmitter 定义了一个特殊的事件 error,它包含了错误的语义,我们在遇到 异常的时候通常会触发 error 事件。
当 error 被触发时,EventEmitter 规定如果没有响 应的监听器,Node.js 会把它当作异常,退出程序并输出错误信息。
我们一般要为会触发 error 事件的对象设置监听器,避免遇到错误后整个程序崩溃。例如:
var events = require('events');
var emitter = new events.EventEmitter();
emitter.emit('error');
运行时会显示以下错误:
node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
Error: Uncaught, unspecified 'error' event.
at EventEmitter.emit (events.js:50:15)
at Object.&anonymous& (/home/byvoid/error.js:5:9)
at Module._compile (module.js:441:26)
at Object..js (module.js:459:10)
at Module.load (module.js:348:31)
at Function._load (module.js:308:12)
at Array.0 (module.js:479:10)
at EventEmitter._tickCallback (node.js:192:40)
继承 EventEmitter
大多数时候我们不会直接使用 EventEmitter,而是在对象中继承它。包括 fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类。
为什么要这样做呢?原因有两点:
首先,具有某个实体功能的对象实现事件符合语义, 事件的监听和发射应该是一个对象的方法。
其次 JavaScript 的对象机制是基于原型的,支持 部分多重继承,继承 EventEmitter 不会打乱对象原有的继承关系。
阅读(...) 评论()跟我学Nodejs(二)--- Node.js事件模块
字体:[ ] 类型:转载 时间:
events是node.js 最重要的模块,events模块只提供了一个对象events.EventEmitter,EventEmitter 的核心是事件发射与事件监听器。
简介及资料
&&& events是node.js 最重要的模块,events模块只提供了一个对象events.EventEmitter,EventEmitter 的核心是事件发射与事件监听器。
&&& Node.js中大部分的模块,都继承自Event模块。
&&& 与DOM树上事件不同,不存在事件冒泡、逐层捕获等行为。
&&& EventEmitter 支持若干个事件监听器。当事件发射时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递。   
&  如何访问:
代码如下:require('events');
emitter.on(event, listener)
代码如下:/*&&& 调用events模块,获取events.EventEmitter对象*/var EventEmitter = require('events').EventE&& var ee = new EventEmitter();/*&&& EventEmitter.on(event, listener) 为事件注册一个监听&&& 参数1:event& 字符串,事件名&&& 参数2:回调函数*/ee.on('some_events', function(foo, bar) {&&& console.log("第1个监听事件,参数foo=" + foo + ",bar="+bar );});console.log('第一轮');ee.emit('some_events', 'Wilson', 'Zhong');console.log('第二轮');ee.emit('some_events', 'Wilson', 'Z');EventEmitter.on(event, listener) 示例源码
emitter.emit(event, [arg1], [arg2], [...])
代码如下:var EventEmitter = require('events').EventE&& var ee = new EventEmitter();ee.on('some_events', function(foo, bar) {&&&&&&&& &&& console.log("第1个监听事件,参数foo=" + foo + ",bar="+bar );});/*&&& EventEmitter.emit(event, [arg1], [arg2], [...])&& 触发指定事件&&& 参数1:event& 字符串,事件名&&& 参数2:可选参数,按顺序传入回调函数的参数&&& 返回值:该事件是否有监听*/var isSuccess = ee.emit('some_events', 'Wilson', 'Zhong');ee.on('some_events', function(foo, bar) {&&&&&&&& &&& console.log("第2个监听事件,参数foo=" + foo + ",bar="+bar );});ee.emit('some_events', 'zhong', 'wei');var isSuccess2 = ee.emit('other_events', 'Wilson', 'Zhong');console.log(isSuccess);console.log(isSuccess2);emitter.emit(event, [arg1], [arg2], [...]) 示例源码
示例进行了三次触发事件操作,其中some_events注册了监听,调用时emit函数会返回一个true,而other_events并没有注册监听,emit函数会返回一个false,表示该事件没有监听;当然也可以不用管这个返回值!
emitter.once(event, listener)
代码如下:var EventEmitter = require('events').EventE&& var ee = new EventEmitter();/*&&& EventEmitter.once(event, listener)& 为事件注册一次性监听,触发一次后移除监听&&& 参数1:event& 字符串,事件名&&& 参数2:回调函数*/ee.once('some_events', function(foo, bar) {&&& console.log("第1个监听事件,参数foo=" + foo + ",bar="+bar );});console.log('第一轮');ee.emit('some_events', 'Wilson', 'Zhong');console.log('第二轮');var isSuccess =& ee.emit('some_events', 'Wilson', 'Zhong');console.log(isSuccess);emitter.once(event, listener) 示例源码
&&& 从上面示例代码执行结果可以看出,用emitter.once给some_events注册一个监听后,分两轮调用emitter.emit触发,第二轮会返回false;这表示用emitter.once注册监听和用前面讲的emitter.on注册监听略有不同,
&&& emitter.once注册监听是一次性监听,当触发一次后,会移除该监听!当然,从名字上就看就比较明显了^_^!
emitter.removeListener(event, listener)
&先来看一个失败的场景~~~
代码如下:var EventEmitter = require('events').EventE&& var ee = new EventEmitter();ee.on('some_events', function(foo, bar) {&&& console.log("第1个监听事件,参数foo=" + foo + ",bar="+bar );});/*&&& 看到API中removeListener移除方法时,以为应该是这样&&& 但是结果^_^!!!!!*/ee.removeListener('some_events', function(){&&& console.log('成功移除事件some_events监听!');&&&&&&& });console.log('第一轮');ee.emit('some_events', 'Wilson', 'Zhong');emitter.removeListener(event, listener) 示例失败场景源码
&&& 当我用emitter.on给some_events注册了一个监听后,我用emiiter.removeListener移除some_events的监听,随后再调用emitter.emit去触发,最后发现不是按我想像的在进行!为什么呢?
&&& 我理所当然的认为emiiter.removeListener第二个参数是个回调函数,API还是要认真看清楚啊!!!
下面再看个成功的场景~~~
代码如下:var EventEmitter = require('events').EventE&& var ee = new EventEmitter();var listener = function(foo,bar){&&& console.log("第1个监听事件,参数foo=" + foo + ",bar="+bar );}var listener2= function(foo,bar){&&& console.log("第2个监听事件,参数foo=" + foo + ",bar="+bar );}var listener3= function(foo,bar){&&& console.log("第3个监听事件,参数foo=" + foo + ",bar="+bar );}ee.on('some_events', listener);ee.on('some_events', listener2);ee.on('some_events', listener3);/*&&& EventEmitter.removeListener(event, listener)& 移除指定事件的监听器&&& 注意:该监听器必须是注册过的&&& PS:上一个例子之后以会失败,很大原因就是忽略了监听器,理所当然的认为传个事件名就OK了,所以就悲剧了!*/ee.removeListener('some_events', listener);ee.removeListener('some_events', listener3);ee.emit('some_events', 'Wilson', 'Zhong');emitter.removeListener(event, listener) 示例成功场景源码
&&& 我用示例中写法,给some_events添加了三个监听,又移除了第一个和第三个监听,最后再用emitter.emit触发some_events,输出结果不难发现,用emitter.removeListener移除的第一个和第三个监听都没有再起作用,
&&& 想当然是害人地,原来emitter.removeListener的第二个参数是要移除的监听,而非移除成功后的回调函数……^_^!
emitter.removeAllListeners([event])
emitter.removeListener用过了,但一个事件可以有多个监听,需要全部移除时,一个个移除明显不是愉快的做法,不符合偷懒的天性!
让我们来体验一下emitter.removeAllListeners带来的便捷!
代码如下:var EventEmitter = require('events').EventE&& var ee = new EventEmitter();var listener = function(foo,bar){&&& console.log("第1个监听事件,参数foo=" + foo + ",bar="+bar );}var listener2= function(foo,bar){&&& console.log("第2个监听事件,参数foo=" + foo + ",bar="+bar );}ee.on('some_events', listener);ee.on('some_events', listener2);ee.on('other_events',function(foo,bar){&&& console.log("其它监听事件,参数foo=" + foo + ",bar="+bar );});/*&&& EventEmitter.removeAllListeners([event])&& 移除(批定事件)所有监听器&&& 参数1:可选参数,event& 字符串,事件名*/ee.removeAllListeners('some_events');ee.emit('some_events', 'Wilson', 'Zhong');ee.emit('other_events', 'Wilson', 'Zhong');emitter.removeAllListeners 传入事件名参数示例源码
&&& 看看上面的执行结果,你会发现给some_events注册了两个监听;给other_events注册了一个监听;我调用emitter.removeAllListeners传了some_events事件名;
&&& 最后使用emitter.on函数触发some_events和other_events两个事件,最后发现some_events注册的两个监听都不存在,而other_events注册的监听还存在;
&&& 这表示当 emitter.removeAllListeners传用事件名作为参数时,为移除传入事件名的所有监听,而不会影响其它事件监听!
emitter.removeAllListeners可以不传用事件名参数;直接执行
代码如下:var EventEmitter = require('events').EventE&& var ee = new EventEmitter();var listener = function(foo,bar){&&& console.log("第1个监听事件,参数foo=" + foo + ",bar="+bar );}var listener2= function(foo,bar){&&& console.log("第2个监听事件,参数foo=" + foo + ",bar="+bar );}ee.on('some_events', listener);ee.on('some_events', listener2);ee.on('other_events',function(foo,bar){&&& console.log("其它监听事件,参数foo=" + foo + ",bar="+bar );});/*&&& EventEmitter.removeAllListeners([event])&& 移除(批定事件)所有监听器&&& 参数1:可选参数,event& 字符串,事件名*/ee.removeAllListeners();ee.emit('some_events', 'Wilson', 'Zhong');ee.emit('other_events', 'Wilson', 'Zhong');emitter.removeAllListeners 不传参数示例源码
&&& 示例代码和传入参数时几乎一样,只是在调用emitter.removeAllListeners并没有传入指定事件名;
&&& 运行结果会发现some_events和other_events所有监听都不存在了,它会移除所有监听!(比较暴力的方法一般要慎用~~)
emitter.listeners(event)
代码如下:var EventEmitter = require('events').EventE&& var ee = new EventEmitter();var listener = function(foo,bar){&&& console.log("第1个监听事件,参数foo=" + foo + ",bar="+bar );}var listener2= function(foo,bar){&&& console.log("第2个监听事件,参数foo=" + foo + ",bar="+bar );}ee.on('some_events', listener);ee.on('some_events', listener2);ee.on('other_events',function(foo,bar){&&& console.log("其它监听事件,参数foo=" + foo + ",bar="+bar );});/*&&& EventEmitter.listeners(event)&& //返回指定事件的监听数组&&& 参数1:event& 字符串,事件名&&& */var listenerEventsArr = ee.listeners('some_events');console.log(listenerEventsArr.length)for (var i = listenerEventsArr.length - 1; i &= 0; i--) {&&& console.log(listenerEventsArr[i]); };emitter.listeners(event) 示例源码
&&& 给some_events注册两个监听,调用emitter.listeners函数,传入some_events事件名,接收函数返回值;
&&& 从结果可以看出,返回值接收到some_events所有注册监听的集合!
emitter.setMaxListeners(n)
&一个事件可以添加多个监听是没错,但Nodejs默认最大值是多少呢?
代码如下:var EventEmitter = require('events').EventE&& var ee = new EventEmitter();/*&&&& 给EventEmitter 添加11个监听*/for (var i = 10; i &= 0; i--) {&&& ee.on('some_events',function()&&& {&&&&&&& console.log('第'+ (i +1) +'个监听');&&& });};添加N个监听示例源码
上面示例中我用个循环给some_events添加11个监听,执行代码,发现warning信息出现,并且提示的比较详细了,需要用emitter.setMaxListeners()去提升限值
代码如下:var EventEmitter = require('events').EventE&& var ee = new EventEmitter();/*&&& EventEmitter.setMaxListeners (n)&& 给EventEmitter设置最大监听&&& 参数1: n 数字类型,最大监听数&&& 超过10个监听时,不设置EventEmitter的最大监听数会提示:&&& (node) warning: possible EventEmitter memory leak detected. 11 listeners added.&&&& Use emitter.setMaxListeners() to increase limit.&&& 设计者认为侦听器太多,可能导致内存泄漏,所以存在这样一个警告*/ee.setMaxListeners(15);/*&&&& 给EventEmitter 添加11个监听*/for (var i = 10; i &= 0; i--) {&&& ee.on('some_events',function()&&& {&&&&&&& console.log('第'+ (i +1) +'个监听');&&& });};emitter.setMaxListeners 示例源码
&&& 当我调用emitter.setMaxListeners传入15时,执行代码,warning信息不再出现;
&&& emitter.setMaxListeners的作用是给EventEmitter设置最大监听数,感觉一般是不需要设置这个值,10个还不够用的情况应该是比较少了!
&&& 设计者认为侦听器太多会导致内存泄漏,所有就给出了一个警告!
&用的比较少的就不详细说了
EventEmitter.defaultMaxListeners
&&& EventEmitter.defaultMaxListeners功能与setMaxListeners类似,&&& 给所有EventEmitter设置最大监听&&& setMaxListeners优先级大于defaultMaxListeners
EventEmitter.listenerCount(emitter, event)
&&& 返回指定事件的监听数
&特殊的事件Error
&&& 引用自Node.js开发指南:EventEmitter 定义了一个特殊的事件 error,它包含了“错误”的语义,我们在遇到 异常的时候通常会发射 error 事件。当 error 被发射时,EventEmitter 规定如果没有响 应的监听器,Node.js 会把它当作异常,退出程序并打印调用栈。我们一般要为会发射 error 事件的对象设置监听器,避免遇到错误后整个程序崩溃。
事件的继承
&&& 以后归到util里再讲一下吧,有兴趣的可以自已看看 http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具面试题(node核心内置类库(事件,流,文件,网络等))_词汇网
面试题(node核心内置类库(事件,流,文件,网络等))
责任编辑:词汇网 发表时间: 14:36:15
node概览1. 为什么要用node?参考答案: 总结起来node有以下几个特点:简单强大,轻量可扩展.简单体现在node使用的是javascript,json来进行编码,人人都会;强大体现在非阻塞IO,可以适应分块传输数据,较慢的网络环境,尤其擅长高并发访问;轻量体现在node本身既是代码,又是服务器,前后端使用统一语言;可扩展体现在可以轻松应对多实例,多服务器架构,同时有海量的第三方应用组件.2. node的构架是什么样子的?参考答案: 主要分为三层,应用app >> V8及node内置架构 >> 操作系统. V8是node运行的环境,可以理解为node虚拟机.node内置架构又可分为三层: 核心模块(javascript实现) >> c++绑定 >> libuv + CAes + http.3. node有哪些核心模块?参考答案: EventEmitter, Stream, FS, Net和全局对象node全局对象1. node有哪些全局对象?参考答案: process, console, Buffer和exports2. process有哪些常用方法?参考答案: process.stdin, process.stdout, process.stderr, process.on, process.env, process.argv, process.arch, process.platform, process.exit3. console有哪些常用方法?参考答案: console., console.error/console.warning, console.time/console.timeEnd, console.trace, console.table4. node有哪些定时功能?参考答案: setTimeout/clearTimeout, setInterval/clearInterval, setImmediate/clearImmediate, process.nextTick5. node中的事件循环是什么样子的?参考答案: event loop其实就是一个事件队列,先加入先执行,执行完一次队列,再次循环遍历看有没有新事件加入队列.但是请务必注意,这一个事件队列的循环,一次只执行一个事件,然后下一次循环再执行一个事件.这是由于javascript的单线程机制导致的,如果一次循环多个事件,就可能会阻塞其它代码的执行.异步执行的叫IO events, setImmediate是在当前队列立即执行,setTimout/setInterval是把执行定时到到后面的队列,process.nextTick是在当前执行完,下次遍历前执行.所以总体顺序是: IO events >> setImmediate >> setTimeout/setInterval(注册事件) >> process.nextTick.6. node中的Buffer如何应用?参考答案: Buffer是用来处理二进制数据的,比如图片,mp3,数据库文件等.Buffer支持各种编码解码,二进制字符串互转.EventEmitter1. 什么是EventEmitter?参考答案: EventEmitter是node中一个实现观察者模式的类,主要功能是监听和发射消息,用于处理多模块交互问题.2. 如何实现一个EventEmitter?参考答案: 主要分三步:定义一个子类,调用构造函数,继承EventEmitter代码演示
var util = require("util");
var EventEmitter = require("events").EventE
function MyEmitter() {
EventEmitter.call(this);
} // 构造函数
util.inherits(MyEmitter, EventEmitter); // 继承
var em = new MyEmitter();
em.on("hello", function(data) {
console.log("收到事件hello的数据:", data);
}); // 接收事件,并打印到控制台
em.emit("hello", "EventEmitter传递消息真方便!");3. EventEmitter有哪些典型应用?参考答案: 1) 模块间传递消息 2) 回调函数内外传递消息 3) 处理流数据,因为流是在EventEmitter基础上实现的. 4) 观察者模式发射触发机制相关应用4. 怎么捕获EventEmitter的错误事件?参考答案: 监听error事件即可.如果有多个EventEmitter,也可以用domain来统一处理错误事件.代码演示
var domain = require("domain");
var myDomain = domain.create();
myDomain.on("error", function(err){
console.log("domain接收到的错误事件:", err);
}); // 接收事件并打印
myDomain.run(function(){
var emitter1 = new MyEmitter();
emitter1.emit("error", "错误事件来自emitter1");
emitter2 = new MyEmitter();
emitter2.emit("error", "错误事件来自emitter2");
});5. EventEmitter中的newListenser事件有什么用处?参考答案: newListener可以用来做事件机制的反射,特殊应用,事件管理等.当任何on事件添加到EventEmitter时,就会触发newListener事件,基于这种模式,我们可以做很多自定义处理.代码演示var emitter3 = new MyEmitter();emitter3.on("newListener", function(name, listener) {
console.log("新事件的名字:", name);
console.log("新事件的代码:", listener);
setTimeout(function(){ console.log("我是自定义延时处理机制"); }, 1000);});emitter3.on("hello", function(){
console.log("hello node");});Stream1. 什么是Stream?参考答案: stream是基于事件EventEmitter的数据管理模式.由各种不同的抽象接口组成,主要包括可写,可读,可读写,可转换等几种类型.2. Stream有什么好处?参考答案: 非阻塞式数据处理提升效率,片断处理节省内存,管道处理方便可扩展等.3. Stream有哪些典型应用?参考答案: 文件,网络,数据转换,音频视频等.4. 怎么捕获Stream的错误事件?参考答案: 监听error事件,方法同EventEmitter.5. 有哪些常用Stream,分别什么时候使用?参考答案: Readable为可被读流,在作为输入数据源时使用;Writable为可被写流,在作为输出源时使用;Duplex为可读写流,它作为输出源接受被写入,同时又作为输入源被后面的流读出.Transform机制和Duplex一样,都是双向流,区别时Transfrom只需要实现一个函数_transfrom(chunk, encoding, callback);而Duplex需要分别实现_read(size)函数和_write(chunk, encoding, callback)函数.6. 实现一个Writable Stream?参考答案: 三步走:1)构造函数call Writable 2) 继承Writable 3) 实现_write(chunk, encoding, callback)函数代码演示var Writable = require("stream").Wvar util = require("util");function MyWritable(options) {
Writable.call(this, options);} // 构造函数util.inherits(MyWritable, Writable); // 继承自WritableMyWritable.prototype._write = function(chunk, encoding, callback) {
console.log("被写入的数据是:", chunk.toString()); // 此处可对写入的数据进行处理
callback();};process.stdin.pipe(new MyWritable()); // stdin作为输入源,MyWritable作为输出源
文件系统1. 内置的fs模块架构是什么样子的?参考答案: fs模块主要由下面几部分组成: 1) POSIX文件Wrapper,对应于操作系统的原生文件操作 2) 文件流 fs.createReadStream和fs.createWriteStream 3) 同步文件读写,fs.readFileSync和fs.writeFileSync 4) 异步文件读写, fs.readFile和fs.writeFile2. 读写一个文件有多少种方法?参考答案: 总体来说有四种: 1) POSIX式低层读写 2) 流式读写 3) 同步文件读写 4) 异步文件读写3. 怎么读取json配置文件?参考答案: 主要有两种方式,第一种是利用node内置的require("data.json")机制,直接得到js对象; 第二种是读入文件入内容,然后用JSON.parse(content)转换成js对象.二者的区别是require机制情况下,如果多个模块都加载了同一个json文件,那么其中一个改变了js对象,其它跟着改变,这是由node模块的缓存机制造成的,只有一个js模块对象; 第二种方式则可以随意改变加载后的js变量,而且各模块互不影响,因为他们都是独立的,是多个js对象.4. fs.watch和fs.watchFile有什么区别,怎么应用?参考答案: 二者主要用来监听文件变动.fs.watch利用操作系统原生机制来监听,可能不适用网络文件系统; fs.watchFile则是定期检查文件状态变更,适用于网络文件系统,但是相比fs.watch有些慢,因为不是实时机制.网络1. node的网络模块架构是什么样子的?参考答案: node全面支持各种网络服务器和客户端,包括tcp, http/https, tcp, udp, dns, tls/ssl等.2. node是怎样支持https,tls的?参考答案: 主要实现以下几个步骤即可: 1) openssl生成公钥私钥 2) 服务器或客户端使用https替代http 3) 服务器或客户端加载公钥私钥证书3. 实现一个简单的http服务器?参考答案: 经典又很没毛意义的一个题目.思路是加载http模块,创建服务器,监听端口.代码演示
var http = require("http"); // 加载http模块
http.createServer(function(req, res) {
res.writeHead(200, {"Content-Type": "text/html"}); // 200代表状态成功, 文档类型是给浏览器识别用的
res.write(" 我是标题啊! 这么原生,初级的服务器,下辈子能用着吗?!"); // 返回给客户端的html数据
res.end(); // 结束输出流
}).listen(3000); // 绑定3ooo, 查看效果请访问 http://localhost:3000 child-process1. 为什么需要child-process?参考答案: node是异步非阻塞的,这对高并发非常有效.可是我们还有其它一些常用需求,比如和操作系统shell命令交互,调用可执行文件,创建子进程进行阻塞式访问或高CPU计算等,child-process就是为满足这些需求而生的.child-process顾名思义,就是把node阻塞的工作交给子进程去做.2. exec,execFile,spawn和fork都是做什么用的?参考答案: exec可以用操作系统原生的方式执行各种命令,如管道 cat ab.txt | execFile是执行一个文件; spawn是流式和操作系统进行交互; fork是两个node程序(javascript)之间时行交互.3. 实现一个简单的命令行交互程序?参考答案: 那就用spawn吧.代码演示
var cp = require("child_process");
var child = cp.spawn("echo", ["你好", "钩子"]); // 执行命令
child.stdout.pipe(process.stdout); // child.stdout是输入流,process.stdout是输出流
// 这句的意思是将子进程的输出作为当前程序的输入流,然后重定向到当前程序的标准输出,即控制台4. 两个node程序之间怎样交互?参考答案: 用fork嘛,上面讲过了.原理是子程序用process.on, process.send,父程序里用child.on,child.send进行交互.代码演示
1) fork-parent.js
var cp = require("child_process");
var child = cp.fork("./fork-child.js");
child.on("message", function(msg){
console.log("老爸从儿子接受到数据:", msg);
child.send("我是你爸爸,送关怀来了!");
2) fork-child.js
process.on("message", function(msg){
console.log("儿子从老爸接收到的数据:", msg);
process.send("我不要关怀,我要银民币!");
});5. 怎样让一个js文件变得像linux命令一样可执行?参考答案: 1) 在myCommand.js文件头部加入 #!/usr/bin/env node 2) chmod命令把js文件改为可执行即可 3) 进入文件目录,命令行输入myComand就是相当于node myComand.js了6. child-process和process的stdin,stdout,stderror是一样的吗?参考答案: 概念都是一样的,输入,输出,错误,都是流.区别是在父程序眼里,子程序的stdout是输入流,stdin是输出流.node高级话题(异步,部署,性能调优,异常调试等)1. node中的异步和同步怎么理解参考答案: node是单线程的,异步是通过一次次的循环事件队列来实现的.同步则是说阻塞式的IO,这在高并发环境会是一个很大的性能问题,所以同步一般只在基础框架的启动时使用,用来加载配置文件,初始化程序什么的.2. 有哪些方法可以进行异步流程的控制?参考答案: 1) 多层嵌套回调 2) 为每一个回调写单独的函数,函数里边再回调 3) 用第三方框架比方async, q, promise等3. 怎样绑定node程序到80端口?参考答案: 多种方式 1) sudo 2) apache/nginx代理 3) 用操作系统的firewall iptables进行端口重定向4. 有哪些方法可以让node程序遇到错误后自动重启?参考答案: 1) runit 2) forever 3) nohup npm start &5. 怎样充分利用多个CPU?参考答案: 一个CPU运行一个node实例6. 怎样调节node执行单元的内存大小?参考答案: 用--max-old-space-size 和 --max-new-space-size 来设置 v8 使用内存的上限7. 程序总是崩溃,怎样找出问题在哪里?参考答案: 1) node --prof 查看哪些函数调用次数多 2) memwatch和heapdump获得内存快照进行对比,查找内存溢出8. 有哪些常用方法可以防止程序崩溃?参考答案: 1) try-catch-finally 2) EventEmitter/Stream error事件处理 3) domain统一控制 4) jshint静态检查 5) jasmine/mocha进行单元测试9. 怎样调试node程序?参考答案: node --debug app.js 和node-inspector常用知名第三方类库(Async, Express等)1. async都有哪些常用方法,分别是怎么用?参考答案: async是一个js类库,它的目的是解决js中异常流程难以控制的问题.async不仅适用在node.js里,浏览器中也可以使用. 1) async.parallel并行执行完多个函数后,调用结束函数
async.parallel([
function(){ ... },
function(){ ... }
], callback);2) async.series串行执行完多个函数后,调用结束函数
async.series([
function(){ ... },
function(){ ... }
]);3) async.waterfall依次执行多个函数,后一个函数以前面函数的结果作为输入参数
async.waterfall([
function(callback) {
callback(null, "one", "two");
function(arg1, arg2, callback) {
// arg1 now equals "one" and arg2 now equals "two"
callback(null, "three");
function(arg1, callback) {
// arg1 now equals "three"
callback(null, "done");
], function (err, result) {
// result now equals "done"
});4) async.map异步执行多个数组,返回结果数组
async.map(["file1","file2","file3"], fs.stat, function(err, results){
// results is now an array of stats for each file
});5) async.filter异步过滤多个数组,返回结果数组
async.filter(["file1","file2","file3"], fs.exists, function(results){
// results now equals an array of the existing files
});2. express项目的目录大致是什么样子的参考答案: app.js, package.json, bin/www, public, routes, views.3. express常用函数参考答案: express.Router路由组件,app.get路由定向,app.configure配置,app.set设定参数,app.use使用中间件4. express中如何获取路由的参数参考答案: /users/:name使用req.params.name来获取; req.body.username则是获得表单传入参数 express路由支持常用通配符 ?, +, *, and ()5. express response有哪些常用方法参考答案: res.download() 弹出文件下载res.end() 结束responseres.json() 返回jsonres.jsonp() 返回jsonpres.redirect() 重定向请求res.render() 渲染模板res.send() 返回多种形式数据res.sendFile 返回文件res.sendStatus() 返回状态其它相关后端常用技术(MongoDB, Redis, Apache, Nginx等)1. mongodb有哪些常用优化措施参考答案: 类似传统数据库,索引和分区.2. mongoose是什么?有支持哪些特性?参考答案: mongoose是mongodb的文档映射模型.主要由Schema, Model和Instance三个方面组成.Schema就是定义数据类型,Model就是把Schema和js类绑定到一起,Instance就是一个对象实例.常见mongoose操作有,save, update, find. findOne, findById, static方法等.2. redis支持哪些功能参考答案: set/get, mset/hset/hmset/hmget/hgetall/hkeys, sadd/smembers, publish/subscribe, expire3. redis最简单的应用参考答案:
var redis = require("redis"),
client = redis.createClient();
client.set("foo_rand", "some fantastic value");
client.get("foo_rand", function (err, reply) {
console.log(reply.toString());
client.end();4. apache,nginx有什么区别?参考答案: 二者都是代理服务器,功能类似.apache应用简单,相当广泛.nginx在分布式,静态转发方面比较有优势.常用前端技术(Html5, CSS3, JQuery等)1. Html5有哪些比较实用新功能参考答案: File API支持本地文件操作; Canvans/SVG支持绘图; 拖拽功能支持; 本地存储支持; 表单多属性验证支持; 原生音频视频支持等2. CSS3/JQuery有哪些学常见选择器参考答案: id, 元素,属性, 值,父子兄弟, 序列等3. JQuery有哪些经典应用参考答案: 文档选择,文档操作,动画, ajax, json, js扩展等.参考资料:/xiaohubei/node-interview-questions/blob/master/README.md
上一集:没有了 下一集:
相关文章:&&&&&&&&&&
最新添加资讯
24小时热门资讯
附近好友搜索

我要回帖

更多关于 deviceeventemitter 的文章

 

随机推荐