nodejs简介
概述
Node.js 采用 Google 开发的 V8 运行代码,使用事件驱动、非阻塞和异步输入输出模型等技术来提高性能,可优化应用程序的传输量和规模。这些技术通常用于数据密集的即时应用程序(javascript 写的后端语言)
特点
- 一个JavaScript运行环境
- 依赖于Chrome V8引擎运行代码解释
- 事件驱动: 在 Node.js 中,客户端请求建立连接,提交数据等行为,会触发相应的事件。Node.js 在一个时刻,只能执行一个事件回调函数,但是在执行一个事件回调函数的中途,可以转而处理其他事件,然后返回继续执行原事件的回调函数
- 非阻塞IO
- 轻量可伸缩: 适用于实时数据交互
- 单线程
安装
自行百度或者google
- 常用命令
node -v 查看安装的node版本
npm -v 查看包安装工具的版本
node; 进入命令行环境(类似于python)可运行简单的命令
node js 全局对象
Node js 中全局对象是global。所有全局对象(除了global本身以外)都是global对象的属性,我们可以直接访问global的属性
常见的全局变量
- __filename
表示当前正在执行的脚本的文件名。它将输出文件所在位置的绝对路径,且和命令行参数所指定的文件名不一定相同
console.log(__filename)
- __dirname
表示当前执行脚本所在的目录。
Hello,world
var http = require("http"); // 加载 http 模块,并将实例化的 HTTP 赋值给变量 http
http
.createServer(function (request, response) {
// 发送 HTTP 头部
// HTTP 状态值: 200 : OK
// 内容类型: text/plain
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("Hello World\n"); // 发送响应数据 "Hello World"
})
.listen(8080);
// 终端打印如下信息
console.log("Server running at http://127.0.0.1:8080/");
打开浏览器输入127.0.0.1:8080
可以看到
Hello World
魅力所在: 简单几行代码即可开启一个简易服务器(nice)
Node.js包
用于管理多个模块及其依赖关系,包的根目录必须包含package.json,一般包含以下字段
- name:包名。包名是唯一的,只能包含小写字母、数字和下划线。
- version:包版本号。
- description:包说明。
- keywords:关键字数组,用于搜索。
- homepage:项目主页。
- bugs:提交 bug 的地址。
- license:许可证。
- maintainers:维护者数组。
- contributors:贡献者数组。
- repositories:项目仓库托管地址数组。
- dependencies:包依赖。
示例代码
{
"name": "guiXu",
"description": "nodejs项目",
"version": "0.1.0",
"keywords": ["GuiXu", "nodejs"],
"maintainers": [
{
"name": "xx",
"email": "xx"
}
],
"contributors": [
{
"name": "xx",
"web": "xxx"
}
],
"bugs": {
"mail": "xx",
"web": "xxx"
},
"licenses": [
{
"type": "Apache License v2",
"url": "http://www.apache.org/licenses/apache2.html"
}
],
"repositories": [
{
"type": "git",
"url": "http://github.com/test/test.git"
}
],
"dependencies": {
"webkit": "1.2",
"ssl": {
"gnutls": ["1.0", "2.0"],
"openssl": "0.9.8"
}
}
}
创建方式:
- 手动创建
npm init命令创建
包命令:
npm install 包名 安装包
npm uodate 包名 更新包
npm uninstall 包名 删除包
模块
一个单独的js文件可被看做一个模块,但想在其他地方使用必须包含导入和导出
导出: module.exports
导入: require(文件路径) require为加载模块
Node.js事件
大多数 Node.js 核心 API 构建于惯用的异步事件驱动架构,其中某些类型的对象(又称触发器,Emitter)会触发命名事件来调用函数(又称监听器,Listener)。
所有能触发事件的对象都是 EventEmitter 类的实例。这些对象有一个 eventEmitter.on() 函数,用于将一个或多个函数绑定到命名事件上。当 EventEmitter 对象触发一个事件时,所有绑定在该事件上的函数都会被同步地调用
EventEmitter类获取
// 引入 events 模块
var events = require("events");
// 创建 eventEmitter 对象
var eventEmitter = new events.EventEmitter();
- 添加监听器
emitter.on(eventName, listener)
使用 emitter.on(eventName, listener) 方法为指定事件注册一个监听器。添加 listener 函数到名为 eventName 的事件的监听器数组的末尾。不会检查 listener 是否已被添加。多次调用并传入相同的 eventName 与 listener 会导致 listener 会被添加多次。
demo
// 引入 events 模块
var events = require("events");
// 创建 emitter 对象
var emitter = new events.EventEmitter();
// 为 connection 事件注册一个监听器
emitter.on("connection", function () {
console.log("已连接");
});
// 一秒后调用监听器
setTimeout(function () {
emitter.emit("connection");
}, 1000);
emitter.prependListener() 方法可用于将事件监听器添加到监听器数组的开头
// 引入 events 模块
var events = require("events");
// 创建 server 对象
var emitter = new events.EventEmitter();
// 为 connection 事件注册一个监听器
emitter.on("connection", function () {
console.log("我是a");
});
// 箭头函数,有兴趣的可以自行了解一下
emitter.prependListener("connection", () => console.log("我是b"));
// 一秒后调用监听器
setTimeout(function () {
emitter.emit("connection");
}, 1000);
- 调用监听器
使用 emitter.emit(eventName[, ...args]) 按照监听器注册的顺序,同步地调用每个注册到名为 eventName 的事件的监听器,并传入提供的参数。如果事件有注册监听返回 true,否则返回 false
// 引入 events 模块
var events = require("events");
// 创建 emitter 对象
var emitter = new events.EventEmitter();
// 定义一个回调函数
var callback1 = function (arg1, arg2) {
console.log("hello world", arg1, arg2);
};
var callback2 = function (arg3, arg4) {
console.log("hello stranger", arg3, arg4);
};
// 为 connection 事件注册监听器
emitter.on("connection", callback1);
emitter.on("connection", callback2);
// 调用监听器
emitter.emit("connection", "愿善良的人", "都能被温柔以待");
- 只执行一次的监听器
eventEmitter.once(eventName, listener) 可以注册最多可调用一次的监听器
- 移除监听器
emitter.removeListener(eventName, listener) 移除监听器。
- 设置监听器最大绑定数
emitter.setMaxListeners(n) 设置同一事件的监听器最大绑定数。默认情况下,如果为特定事件添加了超过 10 个监听器,则 EventEmitter 会打印一个警告,这有助于我们发现内存泄露。显然实际编码中并不是所有的事件都要限制 10 个监听器。
- 查看事件绑定的监听器个数
emitter.listenerCount(eventName) 查看事件绑定的监听器个数
http模块
http 模块主要用于搭建 HTTP 服务端和客户端,要使用 HTTP 服务器和客户端功能必须调用 http 模块
- 创建服务器
http.createServer([requestListener]);
requestListener 是一个请求函数
函数传递有两个参数:request 请求对象 和 response 响应对象。我们调用 request 请求对象的属性和方法就可以拿到所有 HTTP 请求的信息,我们操作 response 响应对象的方法,就可以把 HTTP 响应返回给浏览器。
response 对象常用的方法有:
- response.writeHead(statusCode[, statusMessage][, headers])。表示向请求发送响应头。
参数说明:
- statusCode:状态码,是一个 3 位 HTTP 状态码,如 404 表示网页未找到,200 表示正常。
- statusMessage:可选的,可以将用户可读的
statusMessage作为第二个参数。 - headers:响应头。也就是设置 Content-Type 的值,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件。常用值有:(1)text/html:HTML 格式(2)text/plain:纯文本格式(3)application/x-www-form-urlencoded:数据被编码为名称/值对,这是标准的编码格式。其余的可以自行百度了解,比如 Content-Type 对照表。
response.writeHead(200, { "Content-Type": "text/plain;charset=UTF-8" });
-
response.write()发送一块响应主体,也就是说用来给客户端发送响应数据。可以直接写文本信息,也可以写我们的 html 代码,注意要设置 Content-Type 的值。write 可以使用多次,但是最后一定要使用 end 来结束响应,否则客户端会一直等待 -
response.end()此方法向服务器发出信号,表示已发送所有响应头和主体,该服务器应该视为此消息完成。必须在每个响应上调用方法response.end()
demo
// 加载 http 模块
var http = require("http");
// 创建服务器
http
.createServer(function (request, response) {
// 发送 HTTP 头部
// HTTP 状态值: 200 : OK
// 内容类型: text/html
response.writeHead(200, { "Content-Type": "text/html;charset=UTF-8" });
// 发送响应数据 'hello guixu'
response.write("hello guixu");
// 发送数据 hello world 并且字体为 h1 格式
response.write("<h1>hello world</h1>");
// 结束
response.end();
// 上面的三行代码也可以直接写成 response.end('hello guixu <h1>hello world</h1>');
})
.listen(8080);
// 终端打印如下信息
console.log("Server running at http://127.0.0.1:8080/");
request 对象:
-
request.url获取请求路径,获取到的是端口号之后的那一部分路径,也就是说所有的 url 都是以 / 开头的,判断路径处理响应。 -
request.socket.localAddress获取 ip 地址。 -
request.socket.remotePort获取源端口。
// 1. 创建 Server
var server = http.createServer();
// 2. 监听 request 请求事件,设置请求处理函数
server.on("request", function (req, res) {
console.log("收到请求了,请求路径是:" + req.url);
console.log(
"请求我的客户端的地址是:",
req.socket.remoteAddress,
req.socket.remotePort
);
var url = req.url;
res.writeHead(200, { "Content-Type": "text/html;charset=UTF-8" });
if (url === "/") {
res.end("<h1>Index page</h1>");
} else if (url === "/login") {
res.end("<h1>Login page</h1>");
} else {
res.end("404 Not Found.");
}
});
// 3. 绑定端口号,启动服务
server.listen(8080, function () {
console.log("服务器启动成功,可以访问了。。。");
});
fs模块
文件操作
- 打开文件
fs.open(path, flags[, mode], callback);
demo
// 引入 fs 模块
var fs = require("fs");
// 异步打开文件
fs.open("input.txt", "r+", function (err, fd) {
if (err) {
return console.error(err);
}
console.log("文件打开成功!");
});
此方式为异步方式
同步打开文件的语法
fs.openSync(path, flags[, mode])
- 关闭文件
fs.close(fd, callback);
// 引入 fs 模块
var fs = require("fs");
// 异步打开文件
fs.open("test.txt", "r+", function (err, fd) {
if (err) {
return console.error(err);
}
console.log("文件打开成功!");
// 异步关闭文件
fs.close(fd, function (err) {
if (err) {
console.log(err);
}
console.log("文件关闭成功");
});
});
- 读写文件
fs.read(fd, buffer, offset, length, position, callback);
+ fd:通过 `fs.open()` 方法返回的文件描述符。
+ buffer:是数据写入的缓冲区。
- offset:是缓冲区中开始写入的偏移量。一般它的值我们写为 0。
- length:是一个整数,指定要读取的字节数。
- position:指定从文件中开始读取的位置。如果 position 为 null,则从当前文件位置读取数据,并更新文件位置。
- callback:回调函数,有三个参数 `(err, bytesRead, buffer)`。err 为错误信息,bytesRead 表示读取的字节数,buffer 为缓冲区对象。
demo
// 引入 fs 模块
var fs = require("fs");
// 异步打开文件
fs.open("test.txt", "r+", function (err, fd) {
if (err) {
return console.error(err);
}
console.log("文件打开成功!");
console.log("准备读取文件:");
// 创建一个大小为 1024 字节的缓存区
var buf = Buffer.alloc(1024);
// 异步读取文件
fs.read(fd, buf, 0, buf.length, 0, function (err, bytes, buf) {
if (err) {
console.log(err);
}
console.log(bytes + "字节被读取");
// 仅输出读取的字节
if (bytes > 0) {
console.log(buf.slice(0, bytes).toString());
}
// 异步关闭文件
fs.close(fd, function (err) {
if (err) {
console.log(err);
}
console.log("文件关闭成功");
});
});
});
写入文件
fs.write(fd, buffer, offset, length, position, callback);
参数同读文件操作
// 引入 fs 模块
var fs = require("fs");
// 异步打开文件
fs.open("./test.txt", "a", function (err, fd) {
if (err) {
return console.error(err);
}
console.log("文件打开成功!");
console.log("准备写入文件:");
// 新写入内容为 hello world
var buffer = Buffer.from(new String(" hello world"));
// 异步写入文件
fs.write(fd, buffer, 0, 12, 0, function (err, bytes, buffer) {
if (err) {
throw err;
}
console.log("写入成功");
// 打印出 buffer 中存入的数据
console.log(bytes + "字节被写入");
console.log(buffer.slice(0, bytes).toString());
// 异步关闭文件
fs.close(fd, function (err) {
if (err) {
console.log(err);
}
console.log("文件关闭成功");
});
});
});
- readFile 读取文件--异步
fs.readFile(path, [options], callback);
- writeFile写入文件
fs.writeFile(file, data, [options], callback);