Node.js学习笔记(一)

1、node.js创建第一个应用

node.js是由以下三个部分组成:

  1. 引入require模块:我们可以使用require指令来载入Node.js模块;
  2. 创建服务器:服务器可以监听客户端的请求,类似于Apach、Nginx等http服务器;
  3. 接受请求和相应请求:服务器很容易创建,客户端可以使用浏览器火终端发送http请求,服务器接受请求后返回相应数据。
	// 使用require来载入http模块
	let http = require('http');

	http.createServer((req,res) => {
		// 发送HTTP头部
		// HTTP状态值:200 => OK
		// 内容类型:text/plain
		res.writeHead(200,{'Content-type': 'text/plain'})
		
		// 发送响应数据“Hello World”
		res.end('Hellow World\n');
	}).listen(3000);

	// 终端打印如下信息
	console.log('server running on http://localhost:3000/');

2、Node.js REPL(交互式解释器)

Node.js REPL(Read Eval Pring Loop:交互式解释器)表示一个电脑的环境,类似于Windows 系统的终端或 Unix/Linux shell,我们可以再终端中输入命令,
并接收系统的相应。
Node自带了交互式解释器,并且可以执行以下任务:

  • 读取 —— 读取用户输入,解析输入的javascript数据结构并存储在内存中;
  • 执行 —— 执行输入的数据结构;
  • 打印 —— 输出结果;
  • 循环 —— 循环操作以上步骤,知道用户两次按下ctrl-c按键结束。

3、Node.js回调函数

Node.js的异步编程直接体现就是回调。

一步编程依托于回调来实现,但不能说是使用了回调程序就异步化了。

回调函数一般作为函数的最后一个参数出现:

	function foo1(name, age, callback) { }
	function foo2(value, callback1, callback2) { }

3.1、阻塞代码实例

创建一个input.txt,内容如下

	我永远喜欢阿狸

创建main.js,代码如下:

	let fs = require('fs');

	let data = fs.readFileSync('../input.txt');

	console.log(data.toString());
	console.log('程序执行结束');

程序执行结果:

	> node main.js
	我永远喜欢阿狸
	程序执行结束

3.2、非阻塞代码实例

创建一个input.txt,内容如下:

	我永远喜欢希斯特利亚

再创建main.js,内容如下:

	let fs = require('fs');

	fs.readFile('../input.txt',(err,data) => {
		if(err) console.log(err)
		else {
			console.log(data.toString());
		}
	})

	console.log('程序结束');

结果如下:

	> node main.js
	程序结束
	我永远喜欢希斯特利亚
因此,阻塞是按顺序执行的,非阻塞是不需要按顺序的,所以如果需要处理回调函数的参数,就需要写在回调函数里。

4、Node.js 事件循环

Node.js是单进程单线程应用程序,但是因为V8引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高。

Node.js几乎每一个API都是支持回调函数的。

Node.js中几乎所有的事件机制都是使用设计模式中的观察者模式实现。

Node.js单线程类似进入一个while(true) 事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数。

4.1、事件驱动程序

Node.js使用事件驱动模型,当web server接收到请求,就把它关闭然后进行处理,然后去服务下一个web请求。

当这个请求完成,它被放回处理队列,当到达队列开头,这个结果被返回给用户。

这个模型非常高效,可扩展性非常强,因为webserver一直接收请求而不进行任何读写操作。(这也被称作非阻塞式IO或事件驱动IO)

在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数。
[外链图片转存失败(img-ue436fFh-1562161654041)(readme_files/1.jpg)]

Node.js有多个内置的事件,我们可以通过引入events模块,并通过实例化EventEmitter类来绑定和监听事件,如下实例:

	// 引入events模块
	let events = require('events');

	// 创建eventEmitter对象
	let eventEmitter = new events.EventEmitter();

	// 创建事件处理器
	let eventHandler = function() {
		console.log('连接成功');
		eventEmitter.emit('data_handler');
	}

	// 绑定事件及事件的处理程序
	eventEmitter.on('connection',eventHandler);

	eventEmitter.on('data_handler',function() {
		console.log('处理数据')
	})

	// 触发事件
	eventEmitter.emit('connection');

	console.log('程序执行完毕');

4.2、Node.js应用程序是如何工作的?

在Node应用程序中,执行异步操作的函数将回调函数作为最后一个参数,回调函数接受错误对象作为第一个参数。

接下来重新看看前面的实例,创建一个input.text,内容如下:

	我永远喜欢笠笠笠

然后创建main.js,内容如下:

	let fs = require('fs');

	fs.readFile('../input1.txt',(err,data) => {
		if(err) console.log(err)
		else {
			console.log(data.toString());
		}
	})

	console.log('程序结束')

文件名不对,读取中发生错误,错误err对象就会输出错误信息。

程序结束
	{ [Error: ENOENT: no such file or directory, open 'C:\Users\Documents\HBuilderProjects\my_node\input1.txt']
		errno: -4058,
		code: 'ENOENT',
		syscall: 'open',
		path:
		 'C:\\Users\\Documents\\HBuilderProjects\\my_node\\input1.txt' }

Node.js EventEmitter

Node.js所有的异步I/O操作在完成时都会发送一个事件到事件队列。

Node.js里的许多对象都会分发事件,:一个net.server对象在有新连接是会触发一个事件,一个fs.readStream对象在文件被打开的时候触发一个事件。所有这些产生事件的对象都是events.EventEmitter的实例。

EventEmitter类

events模块只提供了EventEmitter一个对象,EventEmitter对象的核心就是事件触发与事件监听功能的封装。

// 引入events模块
const events = require('events');

// 创建eventEmitter对象
// eventEmitter对象在实例化时发生错误时会触发error事件
// 当添加新的监听器时,newListener事件会触发
// 当监听器被移除时,removerListener事件会触发
let eventEmitter = new events.EventEmitter();

eventEmitter.on('some_event',function() {
	console.log('我永远喜欢阿狸');
})

setTimeout(() => {
	eventEmitter.emit('some_event');
},1000)

EventEmitter 的每个事件由一个事件名和若干个参数组成,事件名是一个字符串,通常表达一定的语义。对于每个事件,EventEmitter 支持若干个事件监听器。

当事件触发时,注册到这个事件上的事件监听器被依次调用,事件参数作为回调参数传递。

// 引入EventEmitter对象
const EventEmitter = require('events').EventEmitter;
// 创建EventEmitter对象实例
let emitter = new EventEmitter();

emitter.on('some_event',function(arg1,arg2) {
	console.log('some_event1',arg1,arg2);
})
emitter.on('some_event',function(arg1,arg2) {
	console.log('some_event2',arg1,arg2);
})
emitter.emit('some_event','我永远喜欢','阿狸');

结果:

> node eventEmitter.js
some_event1 我永远喜欢 阿狸
some_event2 我永远喜欢 阿狸

error事件

EventEmitter 定义了一个特殊的事件error,它包含了错误的语义,我们在遇到异常的时候通常会触发error事件。

当error触发时,如果EventEmitter 没有响应的监听器,Node.js会把它当做异常,退出程序并输出错误信息。

我们一般要为触发error事件的对象绑定监听器,避免遇到错误后整个程序崩溃。

const events = require('events');
let eventEmitter = new events.EventEmitter();
eventEmitter.emit('error');

输出错误信息为:

> node eventEmitter.js
events.js:180
    throw err; // Unhandled 'error' event	没有响应error事件的监听器
    ^

Error [ERR_UNHANDLED_ERROR]: Unhandled error.
    at EventEmitter.emit (events.js:178:17)
    at Object.<anonymous> (C:\Users\Documents\HBuilderProjects\my_node\js\eventEmitter.js:33:14)
    at Module._compile (internal/modules/cjs/loader.js:701:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
    at Module.load (internal/modules/cjs/loader.js:600:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
    at Function.Module._load (internal/modules/cjs/loader.js:531:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:754:12)
    at startup (internal/bootstrap/node.js:283:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)

继承EventEmitter

大多数时候我们不会直接使用EventEmitter,而是在对象中继承它。包括fs、net、http在内的,只要是支持事件响应的核心模块,都是EventEmitter的子类。

这么做的原因有两点:

  1. 首先,具有某个实体功能的对象实现事件符合语义,事件的监听和发生应该是一个对象的方法。
  2. 其次,javascript的对象机制是基于原型的,支持部分多重继承,继承EventEmitter对象不会打乱原有的继承关系。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值