目录
1.Node.js简介
什么是Node.js ?
Node.js 是运行在服务端的JavaScript。
Node.js是一个基于Chrome JavaScript运行时建立的一个平台。
Node.js是一个事件驱动V/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。
Node.js的应用场景
Node.js 的具体场景可以表现为如下: 用户表单收集系统、后台管理系统、实时交互系统、考试系统、联网软件、高并发量的web应用程序。
2.创建第一个应用
2.1引用required模块
在项目的根目录下创建一个叫server.js的文件
我们使用require指令来引入 http模块,并将实例化的HTTP赋值给变量http,实例如下:
var http = require 'http'
2.2创建服务器
接下来我们使用http.createServer()方法创建服务器,并使用listen方法绑定8888端口。函数通过request、response参数来接收和响应数据。 实例如下:
//创建服务器
http.createServer(function(reuest,response){
}).listen(8888);
//终端打印启动信息
console.log('Server running at http://127.0.0.1:8888/')
2.3接收请求与响应请求
//创建服务器
http.createServer(function(reuest,response){
//发送HTTP头部
//HTTP状态值:200(ok)
response.writeHead(200,{'Content-Type':"text/plain"})
//发送响应数据"Hello World"
response.weite("Hello World")
}).listen(8888);
//终端打印启动信息
console.log('Server running at http://127.0.0.1:8888/')
3.模块系统
为了让Node.js 的文件可以相互调用,Node.js 提供了一个简单的模块系统。
模块是Node.js 应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个Node.js 文件就是一个模块,这个文件可能是JavaScript代码、JSON 或者编译过的C/C++扩展。
3.1创建模块
在Node.js 中,创建一个模块非常简单,如下我们创建一个"hello.js”文件,代码如下:
// 创建模块
exports.world = function() {
console.log('Hello World');
}
//另一种方式
function Hello() {
let name;
this.setName = function(theName) {
name = theName;
}
this.sayHello = function() {
console.log(`Hello ${name}`);
}
}
module.exports = Hello
Node.js提供了exports和require两个对象,其中exports,是模块公开的接口,require用于从外部获取一个模块的接口,即所获取模块的exports对象。
接下来我们创建“main.js”文件,代码如下:
var hello = require("./hello");
hello.world();
//另一种方式的接收
var Hello = require('./hello');
const hello = new Hello()
hello.setName("薛之谦");
hello.sayHello()
代码require( ' ./hello')引入了当前目录下的hello.js 文件(./为当前目录,node.js默认后缀为js)。
在以上示例中,hello.js 通过exports对象把 world作为模块的访问接口,在main,js中通过require(./hello')加载这个模块,然后就可以直接访问hello.js 中exports对象的成员函数了。
结果:
4.url模块
4.1引用
Node.js 的URL模块提供了用于分析和解析URL的实用程序。可以调用require('url')来访问它:
const url = require('url');
4.2解析
解析URL对象有以下内容,依赖于它们是否在URl字符串里存在。任何不在URL字符串里的部分,都不会出现在解析对象里
实例:
var url = require('url');
const reqUrl = 'http://user:pass@host.com:8080/p/a/t/h?query=string#hash';
const urlObj = url.parse(reqUrl);
// 获取当前url的端口
console.log(urlObj.port);
// 获取主机
console.log(urlObj.host);
// 获取查询参数
console.log(urlObj.query);
const urlObj2 = url.parse(reqUrl, true)
console.log(urlObj2.query);
4.3URl模块提供的方法
4.3.1url.parse()
url.parse(urlStr[,parseQueryString] [,slashesDenoteHost]):输入URL字符串,返回一个对象
第二个参数为true时,使用querystring来解析查询字符串。如果为true,query属性将会一直赋值为对象,并且search属性将会一直是字符串(可能为空)。默认为false。
实例:
const reqUrl = 'http://user:pass@host.com:8080/p/a/t/h?query=string#hash';
const urlObj = url.parse(reqUrl);
// 获取查询参数
console.log(urlObj.query);
const urlObj2 = url.parse(reqUrl, true)
console.log(urlObj2.query);
第三个参数为true,把//foo/bar当做{host:'foo',pathname:'/bar'},而不是{pathnameL;//foo/bar'}.默认为false
实例:
const reqUrl = "//foo/bar";
const urlObj = url.parse(reqUrl, false);
console.log(urlObj.host, urlObj.pathname);
const urlObj2 = url.parse(reqUrl, false, true);
console.log(urlObj2.host, urlObj2.pathname);
5.路由
我们要为路由提供请求的URL和其他需要的GET及POST参数,随后路由需要根据这些数据来执行相应的代码。
因此,我们需要查看HTTP请求,从中提取出请求的URL以及GET/POST参数。
我们需要的所有数据都会包含在request 对象中,该对象作为onRequest)回调函数的第一个参数传递。但是为了解析这些数据,我们需要额外的NodeJS模块,它们分别是url和querystring模块。
现在,我们来给onRequest()函数加上一些逻辑,用来找出浏览器请求的URL路径。server.js文件代码如下:
var url = require("url");
var http = require("http");
function start(route) {
function OnRequest(request, response) {
let pathname = url.parse(request.url).pathname;
console.log(`接收到${pathname}的请求`);
route(pathname);
response.writeHead(200, { 'Content-Type': "text/plain" });
response.write("Hello Node.js");
response.end()
}
http.createServer(OnRequest).listen(8888)
console.log("服务器已经启动......访问:http://127.0.0.1:8888");
}
exports.start = start
// module.exports = {
// start
// }
好了,我们的应用现在可以通过请求的URL路径来区别不同请求了—―这使我们得以使用路由(还未完成)来将请求以URL路径为基准映射到处理程序上。 现在我们可以来编写路由了,建立一个名为router.js 的文件,添加以下内容:
function router(pathname) {
console.log(`即将路由请求${pathname}`);
}
exports.router = router
同时,我们会相应扩展index.js,使得路由函数可以被注入到服务器中:
var server = require('./server');
var router = require('./router');
server.start(router.router)
6.回调函数
Node.js 异步编程的直接体现就是回调。
回调函数在完成任务后就会被调用,Node使用了大量的回调函数,Node所有API都支持回调函数。
例如,我们可以一边读取文件,一边执行其他命令,在文件读取完成后,我们将文件内容作为回调函数的参数返回。这样在执行代码时就没有阻塞或等待文件IO操作。这就大大提高了Node.js 的性能,可以处理大量的并发请求。
回调函数一般作为函数的最后一个参数出现:
function foo1(name,age,callback){}
function foo2(value,callback,callback2){}
6.1阻塞代码实例
创建一个文件input.txt,内容如下:
天苍苍,野茫茫,风吹草低现牛羊
创建main.js文件,代码如下:
const fs = require("fs");
//同步(阻塞的)
let data = fs.readFileSync("./input.txt")
console.log(data.toString());
console.log("程序执行成功");
执行代码:
$ node main.js
6.2非阻塞代码实例
const fs = require("fs");
// 异步(非阻塞的)
fs.readFile('./input.txt', function(err, data) {
if (err) {
console.error(err.stack);
return;
}
console.log(data.toString());
})
console.log("程序执行完毕");
7.事件循环
Node.js是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高。
Node.js的每一个API都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发。
Node.js基本上所有的事件机制都是用设计模式中观察者模式实现。 Nodejs单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数。
7.1事件驱动程序
Node.js 使用事件驱动模型,当web server接收到请求,就把它关闭然后进行处理,然后去服务下一个web请求。
当这个请求完成,它被放回处理队列,当到达队列开头,这个结果被返回给用户。 这个模型非常高效可扩展性非常强,因为webserver一直接受请求而不等待任何读写操作。(这也被称之为非阻塞式IO或者事件驱动IO) 在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数。
整个事件驱动的流程就是这么实现的,非常简洁。有点类似于观察者模式,事件相当于一个主题(Subject),而所有注册到这个事件上的处理函数相当于观察者(Observer)。 Node.,js有多个内置的事件,我们可以通过引入events模块,并通过实例化EventEmitter类来绑定和监听事件,如下实例:
// 引入 events 模块
const events = require('events');
// 创建 eventEmitter 对象
const eventEmitter = new events.EventEmitter();
以下程序绑定事件处理程序:
// 绑定 connection 事件处理程序
eventEmitter.on('connection', connectHandler);
我们可以通过程序触发事件:
// 触发 connection 事件
eventEmitter.emit('connection');
7.2实例
// 引入 events 模块
const events = require('events');
// 创建 eventEmitter 对象
const eventEmitter = new events.EventEmitter();
// 创建事件处理程序
var connectHandler = function() {
console.log('连接成功');
// 触发 data_received 事件
eventEmitter.emit('data_received');
}
// 绑定 connection 事件处理程序
eventEmitter.on('connection', connectHandler);
// 使用匿名函数绑定 data_receined 事件
eventEmitter.on('data_received', function() {
console.log('数据接收成功');
})
// 触发 connection 事件
eventEmitter.emit('connection');
// 程序执行完毕
console.log("程序执行完毕");
结果: