Node.js篇
# 1. 前置概念
命令行窗口/shell/终端-常用的指令
- dir: 列出当前目录下的所有文件
- cd: 目录名 进入到指定的目录
- md: 目录名 创建一个文件夹
- rd: 目录名 删除一个文件夹
目录
- "." 表示当前目录
- ".." 表示上一级目录
环境变量(windows系统中变量)
- 当我们在命令行窗口打开一个文件,或调用一个程序时,系统会首先在当前目录下寻找文件程序,如果找到了则直接打开;如果没有找到则会依次到环境变量path的路径中寻找,直到找到为止,如果最终没找到则报错
- 所以我们可以将一些经常需要访问的程序和文件的路径添加到path中,这样我们就可以在任意位置来访问这些文件和程序了
I/O (Input/Output)
- I/O操作指的是对磁盘的读写操作
# 2. Node.js简介
- Node是对ES标准一个实现,Node也是一个JS引擎,通过Node可以使js代码在服务器端执行
- Node仅仅对ES标准进行了实现,所以在Node中不包含DOM 和 BOM
- Node中可以使用所有的内建对象,如String Number Boolean Math Date RegExp Function Object Array
- 而BOM和DOM都不能使用,但是可以使用 console 也可以使用定时器
服务器相关
- Node可以在后台来编写服务器,Node编写服务器都是单线程的服务器
- 进程就是一个一个的工作计划(工厂中的车间)
- 线程是计算机最小的运算单位(工厂中的工人),线程是干活的
- 传统的服务器都是多线程的,每进来一个请求,就创建一个线程去处理请求
- Node的服务器是单线程的,Node处理请求时是单线程,但是在后台拥有一个I/O线程池
注意点
- Node就是一款使用js编写的web服务器
- Node底层是使用c++的编写的
- Node的中js引擎使用的Chrome的v8引擎
# 3. Node.js的特点
- 非阻塞、异步的I/O
- 事件和回调函数
- 单线程(主线程单线程,后台I/O线程池)
- 跨平台
# 4. 模块化
ES5中没有原生支持模块化,我们只能通过script标签引入js文件来实现模块化
在Node中为了对模块管理,引入了CommonJS规范
# 4.1 模块的引用
使用 **require()**函数来引入一个模块,它用来加载模块与获取被加载模块导出的对象
用法示例如下:
var 变量 = require("模块的标识");
1
注意
当加载一个模块时node底层会判断这个模块是否被加载过,如果加载过就不再执行而是直接返回这个模块导出的结果的缓存
# 4.2 模块的定义
- 在Node.js中一个js文件就是一个模块
- 默认情况下在js文件中编写的内容,都是运行在一个独立的函数中(Node.js会将这些内容包装成立即执行函数再运行),外部的模块无法访问,内部也无法访问外部
- Node.js会在包装的立即执行函数中声明几个形参如exports、module等
- 模块中使用var声明的变量存在这个独立函数的函数作用域里,外部想要使用这些变量和函数则需要导出
- 不用var而直接声明的是全局变量或函数,要尽量避免使用,防止污染全局作用域
# 4.3 exports
- 每个文件模块中都提供一个exports对象,默认是空对象
- require方法执行的返回值就是被引入模块中exports对象的值(可以使用闭包功能)
- 如果一个模块要直接导出某个成员而非挂载的方式,这时候必须使用对module.exports赋值的方式
# exports导出变量和函数
方式一:使用 exports
exports.属性 = 属性值;
exports.方法 = 函数;
1
2
2
方式二:使用module.exports
module.exports.属性 = 属性值;
module.exports.方法 = 函数;
//用来导出多个数据
module.exports = {};
1
2
3
4
2
3
4
# exports原理
- exports在node中是module.exports的引用
- 由于是引用且返回值是module.exports,因此当给exports或者module.exports重新赋值时,引用的地址就会丢失,就无法导出exports中的值了
/* node模块化的底层实现
var module = {
exports: {}
}
var exports = module.exports
*/
//开始执行文件中的代码
...code
/*
return modeule.exports
*/
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 4.4 模块的标识与加载
- 模块的标识就是模块的名字或路径
- Node.js是通过模块的标识来寻找模块的
对于核心模块(npm中下载的模块),直接使用模块的名字对其进行引入
var fs = require("fs");
var express = require("express");
1
2
2
对于自定义的文件模块,需要通过文件的路径来对模块进行引入,路径可以是绝对路径,如果是相对路径必须以./或 ../开头
var router = require("./router");
1
第三方模块的加载顺序
- 先查找当前父目录下node_modules文件
- 寻找node_modules/xxx文件夹,xxx为加载的模块名称
- 寻找node_modules/xxx/package.json
- 寻找node_modules/xxx/package.json中main属性的文件名
- 按照main文件名加载指定入口文件
- 如果package.json或者main属性值没有指定,则尝试加载package.json所在目录下的index.js
- 没有找到则向上一级目录加载,然后循环1-7
- 到根目录还没有查找到,则报错: can not find module xxx
- node_modules一般放在项目根目录下,不可能一个项目有多个node_modules文件夹
- npm安装规则似乎也相似,只是package.json在node_modules文件夹父目录中而不是项目中的
# 5. npm常用命令
命令 | 作用 |
---|---|
npm -v | 查看npm的版本 |
npm version | 查看所有模块的版本 |
npm search 包名 | 搜索包 |
npm install/i 包名 | 安装包 |
npm remove/r 包名 | 删除包 |
npm install 包名 --save | 安装包并添加到依赖中 |
npm install | 下载当前项目所依赖的包 |
npm install 包名 -g | 全局安装包(全局安装的包一般都是一些工具) |
注意npm i这种简写命令在实际使用时,有如下区别点(windows下):
- 用npm i安装的模块无法用npm uninstall删除,用npm uninstall i才卸载掉
- npm i会帮助检测与当前node版本最匹配的npm包版本号,并匹配出来相互依赖的npm包应该提升的版本号
- 部分npm包在当前node版本下无法使用,必须使用建议版本
- 安装报错时install肯定会出现npm-debug.log 文件,npm i不一定
# 6. 包(package)
将多个模块组合为一个完整的功能,就是一个包
包结构
下属文件夹 | 作用 |
---|---|
bin | 二进制的可执行文件,一般都是一些工具包中才有 |
lib | 存放js源代码文件 |
doc | 文档 |
test | 存放相关测试代码 |
package.json | 包的描述文件 |
# 6.1 package.json
它是一个json格式的文件,在它里面保存了包各种相关的信息
属性 | 具体信息 |
---|---|
name | 包名 |
version | 版本 |
dependencies | 依赖 |
main | 包的主要的文件 |
bin | 可执行文件 |
# 6.2 npm(Node Package Manager)
- npm就是Node.js的包管理器
- 通过npm可以对Node.js中的包进行上传、下载、搜索等操作
- npm会在安装完Node.js以后,自动安装
# 7. 文件系统(File System)
# 7.1 Buffer(缓冲区)
Buffer和数组的结构的非常类似,Buffer是用来存储二进制数据的
Buffer的方法
方法 | 作用 |
---|---|
Buffer.from(字符串) | 将一个字符串中内容保存到一个Buffer中 |
Buffer.toString() | 将buffer转换为一个字符串 |
Buffer.alloc(size) | 创建一个指定大小的buffer对象 |
Buffer.allocUnsafe(size) | 创建一个指定大小的buffer对象,可以包含敏感数据 |
# 7.2 fs模块
在Node通过fs模块来对系统中的文件进行操作,fs模块在Node.js安装时已经一并下载好了,直接引入即可
引入fs方法
var fs = require("fs");
1
fs模块中的大部分操作都提供了两种方法,同步方法和异步方法
- 同步方法带sync
- 异步方法没有sync,都需要回调函数
写入文件
- 同步写入
- 异步写入
- 简单写入
- 流式写入
读取文件
- 同步读取
- 异步读取
- 简单读取
- 流式读取
方法 | 用途 |
---|---|
fs.open(path, flags[, mode], callback) fs.openSync(path, flags[, mode]) | 打开文件 |
fs.write(fd, string[, position[, encoding]], callback) fs.writeSync(fd, string[, position[, encoding]]) fs.read(fd, buffer, offset, length, position, callback) fs.readSync(fd, buffer, offset, length, position) | 读写文件 |
fs.close(fd,callback) fs.closeSync(fd) | 关闭文件 |
fs.writeFile(file, data[, options], callback) fs.writeFileSync(file, data[, options]) fs.readFile(path[, options], callback) fs.readFileSync(path[, options]) | 简单文件读取和写入 |
fs.createWriteStream(path[, options]) fs.createReadStream(path[, options]) | 流式读取和写入,适用于一些比较大的文件 |