简介
-
什么是Node.js?
Node.js 是一个基于 Chrome V8 引擎的 Javascript 运行环境
-
什么是V8引擎?
V8 引擎是一款专门解释和执行 JS 代码的虚拟机,任何程序只要集成了 V8 引擎都可以执行 JS 代码
例如:
- 将 V8 引擎嵌入到浏览器中,那么我们写的 Javascript 代码就会被浏览器所执行
- 将 V8 引擎迁都到 NodeJS 中,那么我们写的 Javascript 代码就会被 NodeJS 所执行
-
什么是运行环境?
运行环境就是生存环境
地球是人类的生存环境
浏览器是网页的生存环境
也就是说运行环境就是特定事物的生存环境
NodeJS 也是一个生存环境,由于NodeJS中集成了 V8 引擎,所以 NodeJS 是 Javascript 的一个生存环境
-
总结:
NodeJS 不是一门编程语言,NodeJS是一个运行环境
由于这个运行环境集成了 V8 引擎,所以在这个运行环境下可以运行我们编写的 JS 代码
这个运行环境最大的特点就是提供了操作系统底层的 API
通过这些底层的 API 我们可以编写出网页中无法实现的功能
安装
下载地址:https://nodejs.org/zh-cn/
程序执行
-
由于浏览器中集成了 V8 引擎,所以浏览器可以解释执行 JS 代码
可以直接在浏览器控制台中执行 JS 代码
可以在浏览器中执行 JS 文件中的 JS 代码
-
由于 NodeJS 中也集成了 V8 引擎,所以 NodeJS 也可以执行 JS 代码
可以直接在命令行工具中编写执行 JS 代码(REPL – Read Eval Print Look:交互式解释器)
可以在命令行工具中执行 JS 文件中的 JS 代码
Node环境和浏览器环境区别
NodeJs 环境和浏览器环境一样都是 JS 的运行环境,都可以执行 JS 代码
但是由于宿主不同,所以特点也有所不同
-
内置对象不同
浏览器环境中提供了 window 全局对象
NodeJS 环境中的全局对象不叫 window,叫 global
-
this默认指向不同
浏览器环境中全局 this 默认指向 window
NodeJS 环境中全局 this 默认指向空对象 {}
-
API不同
浏览器环境中提供了操作节点的 DOM 相关的 API 和 操作浏览器 BOM 相关 API
NodeJS 环境中没有 HTML 节点也没有浏览器,所以 NodeJS环境中没有 DOM/BOM
Node全局对象上的属性
和浏览器一样 Node 环境中的全局对象也提供了很多方法属性供我们使用
- __dirname:当前文件所在文件夹的绝对路径
- __filename:当前文件的绝对路径
- setInterval / clearInterval:和浏览器中 window 对象上的定时器一样
- setTimeout / clearTimeout:和浏览器中 window 对象上的定时器一样
- console:和浏览器中 window 对象上的打印函数一样
Node模块
什么是模块?
-
浏览器开发中的模块
在浏览器开发中为了避免命名冲突,方便维护等等
我们采用类或者立即执行函数的方式来封装 JS 代码,来避免命名冲突和提升代码的维护性
其实这里的一个类或者一个立即执行函数就是浏览器开发中的一个模块
let obj = { // 模块中的业务逻辑代码 }; (function(){ // 模块中的业务逻辑代码 window.xxx = xxx; })();
存在的问题:没有标准没有规范
-
NodeJS开发中的模块
NodeJS采用CommonJS规范实现了模块系统
-
CommonJS规范
CommonJS规范定义了如何定义一个模块,如何暴露(导出)模块中的变量函数,以及如何使用定义好的模块
- 在CommonJS规范中一个文件就是一个模块
- 在CommonJS规范中每个文件中的变量函数都是私有的,对其它文件不可见的
- 在CommonJS规范中每个文件中的变量函数必须通过 exports 暴露(导出)之后其它文件才可以使用
- 在CommonJS规范中想要使用其它文件暴露的变量函数必须通过 require()导入模块才可以使用
// 03-a.js
const name = "zs";
function sum(a, b){
return a + b;
}
exports.name = name;
exports.sum = sum;
// 03-b.js
let aModule = require('./03-a');
console.log(aModule); // { name: 'zs', sum: [Function: sum] }
console.log(aModule.name); // zs
console.log(aModule.sum(10, 20)); // 30
模块导出数据的几种方式
在 NodeJS 中想要导出模块中的变量函数有三种方式
- 通过
exports.xxx = xxx
导出 - 通过
module.exports.xxx = xxx
导出 - 通过
global。xxx = xxx导出
// 方式一
// 04-a.js
const name = "zs";
function sum(a, b){
return a + b;
}
exports.name = name;
exports.sum = sum;
// 04-b.js
const aModule = require("./04-a");
console.log(aModule); // { name: 'zs', sum: [Function: sum] }
// 方式二
// 04-a.js
const name = "ls";
function sum(a, b){
return a + b;
}
module.exports.name = name;
module.exports.sum = sum;
// 04-b.js
const aModule = require('./04-a');
console.log(aModule); // { name: 'ls', sum: [Function: sum] }
// 方式三
// 04-a.js
const name = "ww";
function sum(a, b){
return a + b;
}
global.name = name;
global.sum = sum;
// 04-b.js
require("./04-a")
console.log(global.name); // ww
console.log(global.sum(10, 20)); // 30
注意点:
- 无论通过哪种方式导出,使用时都需要先导入
require
才能使用 - 通过
global.xxx
方式导出不符合 CommonJS 规范,不推荐使用
exports和module.exports区别
exports
只能通过exports.xxx
方式导出数据,不能直接赋值module.exports
既可以通过module.exports.xxx
方式导出数据,也可以直接赋值
注意点:
- 在企业开发中无论哪种方式都不要直接赋值,这个问题只会在面试中出现
require注意点
-
require
导入模块时可以不添加导入模块的类型如果没有指定导入模块的类型,那么会依次查找 .js .json .node文件
无论是三种类型中的哪一种,导入之后都会转换成 JS 对象返回给我们
-
导入自定义模块时必须指定路径
require
可以导入"自定义模块(文件模块)、系统模块(核心模块)、第三方模块"导入”自定义模块“模块时前面必须加上路径
导入"系统模块"和"第三方模块"是不用添加路径
-
导入"系统模块"和"第三方模块"不用添加路径的原因
如果是"系统模块"直接到环境变量配置的路径中查找
如果是"第三方模块"会按照
modules.paths
数组中的路径依次查找
Node包和包管理
-
什么是包?
编写代码的时候尽量遵守单一原则。
也就是一个函数尽量只做一件事情
例如:读取数据函数/写入数据函数/生成随机数函数等等
不要一个函数既读取数据又写入数据又生成随机数
这样代码非常容易出错,也非常难以维护
在模块化开发中也一样,在一个模块(一个文件中)尽量只完成一个特定的功能
但是有些比较复杂的功能可能需要由多个模块组成,
例如:jQuery选择器相关的代码在 A 模块,CSS相关的代码在 B 模块,。。。
我们需要把这些模块组合在一起才是完整的 jQuery
那么这个时候我们就需要一个东西来维护多个模块之间的关系
这个维护多个模块之间的关系的东西就是“包”
简而言之:一个模块就是一个单独的文件,一个包中可以有一个或多个模块
-
NodeJS包的管理
在NodeJS中为了方便开发人员发布、安装和管理包,NodeJS推出了一个包管理工具
NPM(Node Package Manager)
NPM不需要我们单独安装,只要搭建好NodeJS环境就可以自动安装好了
NPM就相当于电脑上的“QQ管家软件助手”,通过NPM我们可以快速找到我们需要的包
可以快速安装我们需要的包,可以快速删除我们不想要的包等等
NPM使用
-
NPM包安装方式
-
全局安装(一般用于安装全局使用的工具,存储在全局node_modules中)
npm install -g 包名
(默认安装最新版本)npm uninstall -g 包名
npm install -g 包名@xxx
(安装指定版本)npm update -g 包名
(更新失败可以直接使用install) -
本地安装(一般用于安装当前项目使用得包,存储在当前项目node_modules中)
npm install 包名
npm install 包名@xxx
npm uninstall 包名
npm update 包名
-
-
初始化本地包
npm init
(初始化package.json文件)npm init -y
(初始化package.json文件)npm install 包名 --save
npm install 包名 --save-dev
包描述文件 package.json,定义了当前项目所需要得各种模块,以及项目得配置信息(比如名称、版本、许可证等元数据)。
npm install
命令根据这个配置文件,自动下载所需的模块,也就是配置项目所需的运行和开发环境-
dependencies:生产环境包的依赖,一个关联数组,由包的名称和版本号组成
-
devDependencies:开发环境包的依赖,一个关联数组,由包的名称和版本号组成
注意点:
-
package.json文件中,不能加入任何注释
-
将项目拷贝给其它人,或者发布的时候,我们不要将node_modules也给别人,因为太大
-
因为有的包可能只在开发阶段需要,但是在上线阶段不需要,所以需要分开指定
npm i
所有的包都会被安装npm i --production
只会安装dependencies中的包npm i --development
只会安装devDependencies中的包 -
NRM
-
什么是nrm?
由于npm默认会去国外下载资源,所以对于国内开发者来说下载会比较慢
所以就有人写了一个nrm工具,允许将资源下载地址从国外切换到国内
npm install -g nrm
安装NRMnrm --version
查看是否安装成功npm ls
查看允许切换的资源地址npm use taobao
将下载地址切换到淘宝ps: 淘宝资源地址和国外的地址内容完全同步。淘宝镜像与官方同步频率为 10 分钟一次以保证尽量与官方服务同步
CNPM
-
什么是cnpm?
由于npm默认会去国外下载资源,所以对于国内开发者来说下载会比较慢
cnpm 就是将下载源从国外切换到国内下载,只不过是将所有的指令从
npm
变为cnpm
而已npm install cnpm -g –registry=https://registry.npm.taobao.org
安装CNPMcnpm -v
查看是否安装成功使用方式同npm,例如:
npm install jquery
变成cnpm install jquery
即可
YARN
-
什么是YARN?
Yarn是由Faceboo、Google、Exponent 和 Tilde 联合推出了一个新的 JS 包管理工具
Yarn 是为了弥补 npm5.0之前的一些缺陷而出现的
注意点:在npm5.0之前,yarn的优势特别明显。但是现在NPM已经更新到了6.9.x甚至7.x了
随着NPM的升级NPM优化甚至超越了Yarn,所以个人还是建议使用NPM
-
NPM的缺陷:
-
npm install
的时候巨慢npm 是按照队列执行每个 package,也就是说必须等到当前 package 安装完成之后,才能继续后面的安装
-
同一个项目,
npm install
的时候无法保持一致性"5.0.3"表示安装指定的5.0.3版本
"~5.0.3"表示安装5.0.x中最新的版本
"^5.0.3"表示安装5.x.x中最新的版本
-
-
-
YARN优点
-
速度快
并行安装:而 Yarn 是同步执行所有人物,提高了性能
离线模式:如果之前已经安装过一个软件包,用 Yarn 再次安装时直接从缓存中获取,就不用像npm那样再从网络下载了
-
安装版本统一
为了防止拉去到不同的版本,Yarn 有一个锁定文件(lock file)记录了被确切安装上的模块的版本号
-
-
-
YARN安装
npm install -g yarn
yarn --version
-
YARN使用
-
安装包
yarn add xxx
yarn add xxx --dev
-
移除包
yarn remove xxx
-
更新包
yarn upgrade xxx --latest
-
全局安装
yarn global add xxx
yarn global upgrade xxx
yarn global remove xxx
-
自定义本地包
-
包的规范
package.json
必须在包的顶层目录下二进制文件应该在bin目录下
JavaScript代码应该在lib目录下
文档应该在doc目录下
单元测试应该在test目录下
-
package.json字段分析
"name": "包的名称,必须是唯一的,由小写英文字母、数字和下划线组成,不能包含空格" "description": "包的简要说明" "version": "符合语义化版本识别规范的版本字符串" "keywords": "关键字数组,通常用于搜索" "maintainers": "维护者数组,每个元素要包含name、email(可选)、web(可选)" "contributors": "贡献者数组,格式与maintainers相同。包的作者应该是贡献者数组的第一个元素" "bugs": "提交bug的地址,可以是网站或者电子邮件地址" "licenses": "许可证数组,每个元素要包含type(许可证名称)和url(链接到许可证文本的地址)" "repositories": "仓库托管地址数组,每个元素要包含type(仓库类型,如git)、url(仓库的地址)和path(相对于仓库的路径,可选)" "dependencies": "生产环境包的依赖,一个关联的数组,由包的名称和版本号组成" "devDependencies": "开发环境包的依赖,一个关联数组,由包的名称和版本号组成"
-
自定义包的实现步骤
创建一个包文件夹
初始化一个
package.json
文件初始化一个包入口js文件
- 如果没有配置
main
,默认会将index.js
作为入口 - 如果包中没有
index.js
,那么就必须配置main
根据包信息配置
package.json
文件- 通过scripts指令可以帮助我们记住指令,然后通过
npm run xxx
方式就可以执行该指令 - 如果指令的名称叫做start或者test,那么执行的时候可以不加run
给
package.json
添加bin属性,告诉系统执行全局命令时需要执行哪一个js文件在全局命令执行的js文件中添加
#!/usr/bin/env node
通过
npm link
将本地包放到全局方便我们调试 - 如果没有配置
-
将自定义包发布到官网
- 在
https://www.npmjs.com/
注册账号 - 淘宝镜像在终端输入npm addUser => 切换npm镜像上传
- npm镜像在终端输入npm publish
- 在
Node核心API
Buffer(缓存)
-
准备知识
计算机只能识别0和1(因为计算机只认识通电和断电两种状态)
所有存储在计算机上的数据都是0和1组成的(数据越大0和1就越多)
计算机中的度量单位
- 1B(Byte字节)= 8bit(位)
0000000
就是一个字节11111111
也是一个字节10101010
也是一个字节- 任意8个 0 或 1 的组合都是一个字节
1 KB = 1024 B
1 MB = 1024 KB
1 GB = 1024 MB
-
什么是Buffer?
Buffer是NodeJS全局对象上的一个类,是一个专门用于存储字节数据的类
NodeJS提供了操作计算机底层API,而计算机底层只能识别0和1
所以就提供了一个专门用于存储字节数据的类
-
如果创建一个Buffer对象
-
创建一个指定大小的Buffer
Buffer.alloc(size[,fill[,encoding]])
-
根据数组/字符串创建一个Buffer对象
Buffer.from(string[,encoding])
let buf = Buffer.alloc(5); console.log(buf); // <Buffer 00 00 00 00 00> let buf1 = Buffer.alloc(1, 9); console.log(buf1); // <Buffer 09> let buf2 = Buffer.from("abc"); console.log(buf2); // <Buffer 61 62 63>
-
-
Buffer对象本质就是一个数组
Buffer实例方法
-
将二进制数据转换成字符串
buf.toString()
返回:转换后的字符串数据
let buf = Buffer.from('abc'); console.log(buf); // <Buffer 61 62 63> conso.log(buf.toString()); // abc
-
往Buffer中写入数据
buf.write(string[,offset[,length]][,encoding])
返回:已写入的字节数
string要写入 buf 的字符串
offset开始写入 string 之前要跳过的字节数。默认值:0
length要写入的字节数。默认值:buf.length - offset
encodingstring 的字符编码。默认值:utf8
let buf = Buffer.alloc(5); console.log(buf); // <Buffer 00 00 00 00 00> // buf.write('abcdefg'); // console.log(buf); // <Buffer 61 62 63 64 65> // buf.write('abcdefg', 2); // console.log(buf); // <Buffer 00 00 61 62 63> // buf.write('abcdefg', 2, 2); // console.log(buf); // <Buffer 00 00 61 62 00>
-
从指定位置截取新Buffer
buf.slice([start,[end]])
let buf = Buffer.alloc(5); buf.write('abcde'); // <Buffer 61 62 63 64 65> // console.log(buf.slice()); // <Buffer 61 62 63 64 65> // console.log(buf.slice(1)); // <Buffer 62 63 64 65> // console.log(buf.slice(1, 3)); // <Buffer 62 63>
Buffer静态方法
-
检查是否支持某种编码格式
Buffer.isEncoding(encoding)
let res = Buffer.isEncoding('utf8'); console.log(res); // true let res2 = Buffer.isEncoding('gbk2312'); console.log(res2); // false
-
检查是否是Buffer类型对象
Buffer.isBuffer(obj)
let obj = {}; let res = Buffer.isBuffer(obj); console.log(res); // false let buf = Buffer.from('123'); let res2 = Buffer.isBuffer(buf); console.log(res2); // true
-
获取Buffer实际字节长度
Buffer.byteLength(string[,encoding])
注意点:一个汉字占用三个字节
let buf = Buffer.from('123'); let res = Buffer.byteLength(buf); console.log(res); // 3 let buf2 = Buffer.from('张三'); let res2 = Buffer.byteLength(buf2);/ console.log(res2); // 6
-
合并Buffer中的数据
Buffer.concat(list[,totalLength])
let buf1 = Buffer.from('123'); let buf2 = Buffer.from('abc'); let res = Buffer.concat([buf1, buf2]); console.log(res); // <Buffer 31 32 33 61 62 63> console.log(res.toString()); // 123abc
Path(路径)
-
路径模块(path)
封装了各种路径相关的操作
和Buffer一样,NodeJS中的路径也是一个特殊的模块
不同的是Buffer模块已经添加到Global上了,所以不需要手动导入
而Path模块没有添加到Global上,所以使用时需要手动导入
const path = require('path');
-
获取路径的最后一部分
path.basename(path[,ext])
const path = require('path'); let res = path.basename('/a/b/c/d/index.html'); console.log(res); // index.html let res2 = path.basename('a/bc/d/index.html', '.html'); console.log(res2); // index
-
获取路径
path.dirname(path)
let res = path.dirname('/a/b//d/index.html'); console.log(res); // a\b\c\d
-
获取扩展名称
path.extname(path)
let res = path.extname('/a/b/c/d/index.html'); console.log(res); // .html
-
判断是否是绝对路径
path.isAbsolute(path)
let res = path.isAbsolute('/a/b/c/d/index.html'); console.log(res); // true let res2 = path.isAbsolute('c:\\a\\b\\c\\d\\index.html'); console.log(res2); // true let res3 = path.isAbsolute('a/c/d/index.html'); console.log(res3); // false
-
获取当前操作系统路径分隔符
path.sep
(windows是\
Linux是/
)let res = path.sep; console.log(res); // \
-
获取当前路径环境变量分隔符
path.delimiter
(windows中使用;
Linux中使用:
)let res = path.delimiter; console.log(res); // ;
-
将路径转换成对象
path.parse(path)
let res = path.parse('/a/b/c/index.html'); // { // root: '/', // dir: '/a/b/c', // base: 'index.html', // ext: '.html', // name: 'index' // } console.log(res);
-
将对象转成路径
path.format(pathObject)
let obj = { root: '/', dir: '/a/b/c', base: 'index.html', ext: '.html', name: 'index' } let res = path.format(obj); console.log(res); // /a/b/c\index.html
-
拼接路径
path.join([...paths])
注意点:
- 如果参数中没有/,那么该方法会自动添加
- 如果参数中有…,那么会自动根据前面的参数生成路径,去到上一级路径
let res = path.join('/a/b', 'c');
console.log(res); // \a\b\c
let res2 = path.join('/a/b', './c');
console.log(res2); // \a\b\c
let res3 = path.join('/a/b', '../');
console.log(res3); // \a\
-
规范化路径
path.normalize(path)
let res = path.normalize('/a//b///cd/index.html'); console.log(res); // \a\b\c\d\index.html
-
计算相对路径
path.relative(from, to)
let res = path.relative('/a/b/c/index.html', '/a/b/d/home.js'); console.log(res); // ..\..\d\home.js
-
解析路径
path.resolve([...paths])
注意点:
- 如果后面的参数是绝对路径,那么前面的参数就会被忽略
let res = path.resolve('/a/b', '/c'); console.log(res); // D:\c let res2 = path.resolve('/a/b', './c'); console.log(res2); // D:\a\b\c let res3 = path.resolve('/a/b', '../c') console.log(res3); // D:\a\c
FS(文件模块)
-
查看文件状态
fs.state(path[, options], callback)
fs.statSync(path[, options])
const fs = require('fs'); // 异步 fs.stat(__filename, function (err, stats) { // birthtime:创建时间 // mtime:文件中的内容发生变化,文件修改的时间 // console.log(stats); if(stats.isFile()){ console.log('这是一个文件'); }else if(stats.isDirectory()){ console.log('这是一个文件夹'); } }) // 同步 let res = fs.statSync(__filename) console.log(res)
-
文件读取
fs.readFile(path[, options], callback)
fs.readFileSync(path[, options])
注意点:
- 没有指定第二个参数,默认会将读取到的数据放到Buffer中
- 第二个参数指定为utf8,返回的数据就是字符串
const fs = require('fs'); const path = require('path'); // 1.拼接需要读取文件的路径 let str = path.join(__dirname, 'data.txt'); // 2.读取文件 // 异步 fs.readFile(str, 'utf-8', function (err, data) { if(err){ throw new Error('读取文件失败'); } console.log(data); // 这是一个文本文件 }) // 同步 let res = fs.readFileSync(str, "utf-8"); console.log(res); // 这是一个文本文件
-
文件写入
fs.writeFile(file, data[, options], callback)
fs.writeFileSync(file, data[, options])
const fs = require('fs'); const path = require('path'); // 1.拼接需要写入的路径 let str = path.join(__dirname, 'zxy.txt'); // 2.写入数据 // 异步 /* fs.writeFile(str, '测试的数据', 'utf8', function (err, status) { if(err){ throw new Error('文件写入失败'); }else { console.log('文件写入成功'); } }) */ // 写入buffer数据 /* let buf = Buffer.from('测试数据2'); fs.writeFile(str, buf, 'utf8', function (err, status) { if(err){ throw new Error('数据写入失败'); }else { console.log('数据写入成功'); } }) */ // 同步 let res = fs.writeFileSync(str, '同步的测试数据', 'utf8'); console.log(res); // undefined => 成功
-
文件追加
fs.appendFile(path, data[, options], callback)
fs.appendFileSync(path, data[, options])
const path = require('path'); const fs = require('fs'); // 1.获取需要追加的文件目录 let str = path.join(__dirname, 'zxy.txt'); // 2.追加数据 // 异步 /* fs.appendFile(str, '追加的数据', 'utf8', function (err, status){ if(err){ throw new Error('追加数据失败'); }else { console.log('追加数据成功'); } }) */ // 同步 let res = fs.appendFileSync(str, '同步追加的数据', 'utf8'); console.log(res); // undefined => 成功
-
大文件操作
前面的文件读取和文件写入都是一次性将数据写入内存或者一次性写入到文件中
但是如果数据比较大,我们将所有数据都读到内存中会导致计算机内存爆炸,卡顿,死机等
所以对于比较大的文件我们需要分批读取和写入
fs.createReadStream(path, [options])
const path = require('path'); const fs = require('fs'); // 1.获取需要读取文件的路径 let str = path.join(__dirname, 'zxy.txt'); // 2.分批读取 let readStream = fs.createReadStream(str, {encoding : 'utf8', highWaterMark : 1}) readStream.on('open', function () { console.log('数据流和文件建立关系成功'); }) readStream.on('error', function () { console.log('数据流和文件建立关系失败'); }) readStream.on('data', function (data) { console.log('从文件中读取到了数据', data); }) readStream.on('close', function () { console.log('数据流和文件断开了关系,并且数据已经读取完毕'); })
fs.createWriteStream(path[, options])
const path = require('path'); const fs = require('fs'); // 1.获取需要写入文件的路径 let str = path.join(__dirname, 'zxy.txt'); // 2.写入文件 let writeStream = fs.createWriteStream(str, {encoding : 'utf8'}); writeStream.on('open', function () { console.log('数据流和文件建立关系成功'); }) writeStream.on('error', function () { console.log('数据流和文件建立关系失败'); }) writeStream.on('close', function () { console.log('数据流和文件断开了关系,并且数据已经读取完毕'); }) let data = '偶尔我也会孤独'; let index = 0; let timerId = setInterval(function () { let ch = data[index]; index++; writeStream.write(ch); console.log('本次写入了', ch); if (index === data.length){ clearInterval(timerId); // 写入需要手动关闭关系 writeStream.end(); } }, 1000)
文件拷贝练习
const path = require('path'); const fs = require('fs'); // 1.生成读取和写入的路径 let readPath = path.join(__dirname, 'test.mp4'); let writePath = path.join(__dirname, 'abc.mp4'); // 2.创建读取流 let readStream = fs.createReadStream(readPath); // 3.创建写入流 let writeStream = fs.createWriteStream(writePath); // 4.监听读取流事件 readStream.on('open', function () { console.log('数据流和文件建立关系成功'); }) readStream.on('error', function () { console.log('数据流和文件建立关系失败'); }) readStream.on('data', function (data) { writeStream.write(data) console.log('从文件中读取到了数据', data); }) readStream.on('close', function () { writeStream.end(); console.log('数据流和文件断开了关系,并且数据已经读取完毕'); }) // 5.监听写入流事件 writeStream.on('open', function () { console.log('数据流和文件建立关系成功'); }) writeStream.on('error', function () { console.log('数据流和文件建立关系失败'); }) writeStream.on('close', function () { console.log('数据流和文件断开了关系,并且数据已经读取完毕'); })
pipe拷贝文件
const path = require('path'); const fs = require('fs'); // 1.生成读取和写入路径 let readPath = path.join(__dirname, 'test.mp4'); let writePath = path.join(__dirname, 'ddd.mp4'); // 2.创建读取流 let readStream = fs.createReadStream(readPath); // 3.创建写入流 let writeStream = fs.createWriteStream(writePath); // 4.利用读取流的管道方法来快速实现文件拷贝 readStream.pipe(writeStream);
-
目录操作
创建目录
fs.mkdir(path[, mode], callback)
fs.mkdirSync(path[, mode])
const path = require('path'); const fs = require('fs'); // 1.生成目录路径 let str = path.join(__dirname, 'ccc'); // 2.创建目录 fs.mkdir(str, function (err) { if(err){ throw new Error('目录创建失败'); }else { console.log('目录创建成功'); } })
读取目录
fs.readdir(path[, options], callback)
fs.readdirSync(path[, options])
const path = require('path'); const fs = require('fs'); fs.readdir(__dirname, function (err, files) { if(err){ throw new Error('读取失败'); }else { files.forEach(function (file) { let filePath = path.join(__dirname, file); let stats = fs.statSync(filePath); if(stats.isFile()){ console.log('这是一个文件', filePath); }else if(stats.isDirectory()){ console.log('这是一个目录', filePath); } }) } })
删除目录
fs.rmdir(path, callback)
fs.rmdirSync(path)
const path = require('path'); const fs = require('fs'); // 1.获取删除目录路径 let str = path.join(__dirname, 'ccc'); // 2.删除目录 fs.rmdir(str, function (err) { if(err){ throw new Error('目录删除失败'); }else { console.log('目录删除成功'); } })
目录操作练习
const path = require('path'); const fs = require('fs'); class CreateProject{ constructor(rootPath, projectName) { this.rootPath = rootPath; this.projectName = projectName; this.subFiles = ['images', 'css', 'js', 'index.html']; } initProject(){ // 1.创建站点文件夹 let projectPath = path.join(this.rootPath, this.projectName); fs.mkdirSync(projectPath); // 2.创建子文件和子目录 this.subFiles.forEach(function (fileName) { if(path.extname(fileName) === ''){ console.log(projectPath); let dirPath = path.join(projectPath, fileName); fs.mkdirSync(dirPath); }else { let filePath = path.join(projectPath, fileName); fs.writeFileSync(filePath, ''); } }) } } let cp = new CreateProject(__dirname, 'jd'); cp.initProject();
HTTP
-
什么是HTTP模块
通过Node.js提供的http模块,我们可以快速的构建一个web服务器
也就是快速实现过去PHP服务器的功能(接受浏览器请求、响应浏览器请求等)
-
通过HTTP模块实现服务器功能步骤
导入HTTP哦快
创建服务器实例对象
绑定请求事件
监听指定端口请求
const http = require('http'); /* // 1.创建服务器实例对象 let server = http.createServer(); // 2.注册请求监听 server.on('request', function (req, res) { // writeHead方法的作用:告诉浏览器返回的是什么数据类型的,返回的数据需要用什么字符集来解析 res.writeHead(200, { "Content-type": "text/palin; charset=utf-8" }); // end方法的作用:本次请求并且返回数据 // res.end('123'); res.end("答应不爱你"); }) // 3.指定监听的端口 server.listen(3000); */ // 简写 http.createServer(function (req, res) { // writeHead方法的作用:告诉浏览器返回的是什么数据类型的,返回的数据需要用什么字符集来解析 res.writeHead(200, { "Content-type": "text/palin; charset=utf-8" }); // end方法的作用:本次请求并且返回数据 // res.end('123'); res.end("答应不爱你2"); }).listen(3000);
-
路径分发
-
什么是路径分发?
路径分发也称之为路由,就是根据不同的请求路径返回不同的数据
-
如何根据不同的请求路径返回不同的数据
通过请求监听方法中的request对象,我们可以获取到当前请求的路径
通过判断请求路径的地址就可以实现不同的请求路径返回不同的数据
const http = require('http'); // request对象其实就是 http.IncomingMessage 类的实例 // response对象其实就是 http.ServerResponse 类的实例 http.createServer(function (req, res) { res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' }) if(req.url.startsWith('/index')){ // 如果通过end方法来返回数据,那么只会返回一次 // res.end('首页'); // res.end('首页2'); // 如果通过write方法来返回数据,那么可多次返回 // write方法不具备结束本次请求的功能,所以还需要手动调用end方法来结束本次请求 res.write('首页'); res.write('首页2'); res.end(); }else if(req.url.startsWith('/login')){ res.end('登录') }else { res.end('没有数据'); } }).listen(3000);
-
-
响应静态网页
拿到用户请求路径之后,只需要利用fs模块将对应的网页返回即可
const http = require('http'); const path = require('path'); const fs = require('fs'); http.createServer(function (req, res) { readFile(req, res); }).listen(3000) function readFile(req, res){ let filePath = path.join(__dirname, 'www', req.url); fs.readFile(filePath, 'utf8', function (err, content) { if(err){ res.end("Server Error"); } res.end(content); }) }
-
响应静态资源
在给浏览器返回数据的时候
如果没有指定响应头的信息
如果没有设置返回数据的类型
那么浏览器不一定能正确的解析
所以无论发挥什么类型的静态资源都需要添加对应的响应头信息
const http = require('http'); const path = require('path'); const fs = require('fs'); const mime = require('./mime.json') http.createServer(function (req, res) { readFile(req, res); }).listen(3000); function readFile(req, res){ let filePath = path.join(__dirname, 'www', req.url); // 加载其它资源不能写utf8 // 如果服务器在响应数据的时候没有指定响应头,那么在有的浏览器上,响应的数据可能无法显示 let extName = path.extname(filePath); let type = mime[extName]; if(type.startsWith('text')){ type += ';charset=utf-8;' } res.writeHead(200, { 'Content-Type' : type }) fs.readFile(filePath, function (err, data) { if(err){ res.end('Server Error'); } res.end(data); }) }
-
响应静态资源封装
// 19.js const http = require('http'); const path = require('path'); const ss = require('./StaticServer') http.createServer(function (req, res) { let rootPath = path.join('D:\\桌面\\www') ss.StaticServer(req, res, rootPath) }).listen(3000);
// StaticServer.js const path = require('path'); const fs = require('fs'); const mime = require('./mime.json') function readFile(req, res, rootPath){ let filePath = path.join(rootPath, req.url); // 加载其它资源不能写utf8 // 如果服务器在响应数据的时候没有指定响应头,那么在有的浏览器上,响应的数据可能无法显示 let extName = path.extname(filePath); let type = mime[extName]; if(type.startsWith('text')){ type += ';charset=utf-8;' } res.writeHead(200, { 'Content-Type' : type }) fs.readFile(filePath, function (err, data) { if(err){ res.end('Server Error'); } res.end(data); }) } exports.StaticServer = readFile;
// mime.json { ".323": "text/h323", ".3gp": "video/3gpp", ".aab": "application/x-authoware-bin", ".aam": "application/x-authoware-map", ".aas": "application/x-authoware-seg", ".acx": "application/internet-property-stream", ".ai": "application/postscript", ".aif": "audio/x-aiff", ".aifc": "audio/x-aiff", ".aiff": "audio/x-aiff", ".als": "audio/X-Alpha5", ".amc": "application/x-mpeg", ".ani": "application/octet-stream", ".apk": "application/vnd.android.package-archive", ".asc": "text/plain", ".asd": "application/astound", ".asf": "video/x-ms-asf", ".asn": "application/astound", ".asp": "application/x-asap", ".asr": "video/x-ms-asf", ".asx": "video/x-ms-asf", ".au": "audio/basic", ".avb": "application/octet-stream", ".avi": "video/x-msvideo", ".awb": "audio/amr-wb", ".axs": "application/olescript", ".bas": "text/plain", ".bcpio": "application/x-bcpio", ".bin ": "application/octet-stream", ".bld": "application/bld", ".bld2": "application/bld2", ".bmp": "image/bmp", ".bpk": "application/octet-stream", ".bz2": "application/x-bzip2", ".c": "text/plain", ".cal": "image/x-cals", ".cat": "application/vnd.ms-pkiseccat", ".ccn": "application/x-cnc", ".cco": "application/x-cocoa", ".cdf": "application/x-cdf", ".cer": "application/x-x509-ca-cert", ".cgi": "magnus-internal/cgi", ".chat": "application/x-chat", ".class": "application/octet-stream", ".clp": "application/x-msclip", ".cmx": "image/x-cmx", ".co": "application/x-cult3d-object", ".cod": "image/cis-cod", ".conf": "text/plain", ".cpio": "application/x-cpio", ".cpp": "text/plain", ".cpt": "application/mac-compactpro", ".crd": "application/x-mscardfile", ".crl": "application/pkix-crl", ".crt": "application/x-x509-ca-cert", ".csh": "application/x-csh", ".csm": "chemical/x-csml", ".csml": "chemical/x-csml", ".css": "text/css", ".cur": "application/octet-stream", ".dcm": "x-lml/x-evm", ".dcr": "application/x-director", ".dcx": "image/x-dcx", ".der": "application/x-x509-ca-cert", ".dhtml": "text/html", ".dir": "application/x-director", ".dll": "application/x-msdownload", ".dmg": "application/octet-stream", ".dms": "application/octet-stream", ".doc": "application/msword", ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ".dot": "application/msword", ".dvi": "application/x-dvi", ".dwf": "drawing/x-dwf", ".dwg": "application/x-autocad", ".dxf": "application/x-autocad", ".dxr": "application/x-director", ".ebk": "application/x-expandedbook", ".emb": "chemical/x-embl-dl-nucleotide", ".embl": "chemical/x-embl-dl-nucleotide", ".eps": "application/postscript", ".epub": "application/epub+zip", ".eri": "image/x-eri", ".es": "audio/echospeech", ".esl": "audio/echospeech", ".etc": "application/x-earthtime", ".etx": "text/x-setext", ".evm": "x-lml/x-evm", ".evy": "application/envoy", ".exe": "application/octet-stream", ".fh4": "image/x-freehand", ".fh5": "image/x-freehand", ".fhc": "image/x-freehand", ".fif": "application/fractals", ".flr": "x-world/x-vrml", ".flv": "flv-application/octet-stream", ".fm": "application/x-maker", ".fpx": "image/x-fpx", ".fvi": "video/isivideo", ".gau": "chemical/x-gaussian-input", ".gca": "application/x-gca-compressed", ".gdb": "x-lml/x-gdb", ".gif": "image/gif", ".gps": "application/x-gps", ".gtar": "application/x-gtar", ".gz": "application/x-gzip", ".h": "text/plain", ".hdf": "application/x-hdf", ".hdm": "text/x-hdml", ".hdml": "text/x-hdml", ".hlp": "application/winhlp", ".hqx": "application/mac-binhex40", ".hta": "application/hta", ".htc": "text/x-component", ".htm": "text/html", ".html": "text/html", ".hts": "text/html", ".htt": "text/webviewhtml", ".ice": "x-conference/x-cooltalk", ".ico": "image/x-icon", ".ief": "image/ief", ".ifm": "image/gif", ".ifs": "image/ifs", ".iii": "application/x-iphone", ".imy": "audio/melody", ".ins": "application/x-internet-signup", ".ips": "application/x-ipscript", ".ipx": "application/x-ipix", ".isp": "application/x-internet-signup", ".it": "audio/x-mod", ".itz": "audio/x-mod", ".ivr": "i-world/i-vrml", ".j2k": "image/j2k", ".jad": "text/vnd.sun.j2me.app-descriptor", ".jam": "application/x-jam", ".jar": "application/java-archive", ".java": "text/plain", ".jfif": "image/pipeg", ".jnlp": "application/x-java-jnlp-file", ".jpe": "image/jpeg", ".jpeg": "image/jpeg", ".jpg": "image/jpeg", ".jpz": "image/jpeg", ".js": "application/x-javascript", ".jwc": "application/jwc", ".kjx": "application/x-kjx", ".lak": "x-lml/x-lak", ".latex": "application/x-latex", ".lcc": "application/fastman", ".lcl": "application/x-digitalloca", ".lcr": "application/x-digitalloca", ".lgh": "application/lgh", ".lha": "application/octet-stream", ".lml": "x-lml/x-lml", ".lmlpack": "x-lml/x-lmlpack", ".log": "text/plain", ".lsf": "video/x-la-asf", ".lsx": "video/x-la-asf", ".lzh": "application/octet-stream", ".m13": "application/x-msmediaview", ".m14": "application/x-msmediaview", ".m15": "audio/x-mod", ".m3u": "audio/x-mpegurl", ".m3url": "audio/x-mpegurl", ".m4a": "audio/mp4a-latm", ".m4b": "audio/mp4a-latm", ".m4p": "audio/mp4a-latm", ".m4u": "video/vnd.mpegurl", ".m4v": "video/x-m4v", ".ma1": "audio/ma1", ".ma2": "audio/ma2", ".ma3": "audio/ma3", ".ma5": "audio/ma5", ".man": "application/x-troff-man", ".map": "magnus-internal/imagemap", ".mbd": "application/mbedlet", ".mct": "application/x-mascot", ".mdb": "application/x-msaccess", ".mdz": "audio/x-mod", ".me": "application/x-troff-me", ".mel": "text/x-vmel", ".mht": "message/rfc822", ".mhtml": "message/rfc822", ".mi": "application/x-mif", ".mid": "audio/mid", ".midi": "audio/midi", ".mif": "application/x-mif", ".mil": "image/x-cals", ".mio": "audio/x-mio", ".mmf": "application/x-skt-lbs", ".mng": "video/x-mng", ".mny": "application/x-msmoney", ".moc": "application/x-mocha", ".mocha": "application/x-mocha", ".mod": "audio/x-mod", ".mof": "application/x-yumekara", ".mol": "chemical/x-mdl-molfile", ".mop": "chemical/x-mopac-input", ".mov": "video/quicktime", ".movie": "video/x-sgi-movie", ".mp2": "video/mpeg", ".mp3": "audio/mpeg", ".mp4": "video/mp4", ".mpa": "video/mpeg", ".mpc": "application/vnd.mpohun.certificate", ".mpe": "video/mpeg", ".mpeg": "video/mpeg", ".mpg": "video/mpeg", ".mpg4": "video/mp4", ".mpga": "audio/mpeg", ".mpn": "application/vnd.mophun.application", ".mpp": "application/vnd.ms-project", ".mps": "application/x-mapserver", ".mpv2": "video/mpeg", ".mrl": "text/x-mrml", ".mrm": "application/x-mrm", ".ms": "application/x-troff-ms", ".msg": "application/vnd.ms-outlook", ".mts": "application/metastream", ".mtx": "application/metastream", ".mtz": "application/metastream", ".mvb": "application/x-msmediaview", ".mzv": "application/metastream", ".nar": "application/zip", ".nbmp": "image/nbmp", ".nc": "application/x-netcdf", ".ndb": "x-lml/x-ndb", ".ndwn": "application/ndwn", ".nif": "application/x-nif", ".nmz": "application/x-scream", ".nokia-op-logo": "image/vnd.nok-oplogo-color", ".npx": "application/x-netfpx", ".nsnd": "audio/nsnd", ".nva": "application/x-neva1", ".nws": "message/rfc822", ".oda": "application/oda", ".ogg": "audio/ogg", ".oom": "application/x-AtlasMate-Plugin", ".p10": "application/pkcs10", ".p12": "application/x-pkcs12", ".p7b": "application/x-pkcs7-certificates", ".p7c": "application/x-pkcs7-mime", ".p7m": "application/x-pkcs7-mime", ".p7r": "application/x-pkcs7-certreqresp", ".p7s": "application/x-pkcs7-signature", ".pac": "audio/x-pac", ".pae": "audio/x-epac", ".pan": "application/x-pan", ".pbm": "image/x-portable-bitmap", ".pcx": "image/x-pcx", ".pda": "image/x-pda", ".pdb": "chemical/x-pdb", ".pdf": "application/pdf", ".pfr": "application/font-tdpfr", ".pfx": "application/x-pkcs12", ".pgm": "image/x-portable-graymap", ".pict": "image/x-pict", ".pko": "application/ynd.ms-pkipko", ".pm": "application/x-perl", ".pma": "application/x-perfmon", ".pmc": "application/x-perfmon", ".pmd": "application/x-pmd", ".pml": "application/x-perfmon", ".pmr": "application/x-perfmon", ".pmw": "application/x-perfmon", ".png": "image/png", ".pnm": "image/x-portable-anymap", ".pnz": "image/png", ".pot,": "application/vnd.ms-powerpoint", ".ppm": "image/x-portable-pixmap", ".pps": "application/vnd.ms-powerpoint", ".ppt": "application/vnd.ms-powerpoint", ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation", ".pqf": "application/x-cprplayer", ".pqi": "application/cprplayer", ".prc": "application/x-prc", ".prf": "application/pics-rules", ".prop": "text/plain", ".proxy": "application/x-ns-proxy-autoconfig", ".ps": "application/postscript", ".ptlk": "application/listenup", ".pub": "application/x-mspublisher", ".pvx": "video/x-pv-pvx", ".qcp": "audio/vnd.qcelp", ".qt": "video/quicktime", ".qti": "image/x-quicktime", ".qtif": "image/x-quicktime", ".r3t": "text/vnd.rn-realtext3d", ".ra": "audio/x-pn-realaudio", ".ram": "audio/x-pn-realaudio", ".rar": "application/octet-stream", ".ras": "image/x-cmu-raster", ".rc": "text/plain", ".rdf": "application/rdf+xml", ".rf": "image/vnd.rn-realflash", ".rgb": "image/x-rgb", ".rlf": "application/x-richlink", ".rm": "audio/x-pn-realaudio", ".rmf": "audio/x-rmf", ".rmi": "audio/mid", ".rmm": "audio/x-pn-realaudio", ".rmvb": "audio/x-pn-realaudio", ".rnx": "application/vnd.rn-realplayer", ".roff": "application/x-troff", ".rp": "image/vnd.rn-realpix", ".rpm": "audio/x-pn-realaudio-plugin", ".rt": "text/vnd.rn-realtext", ".rte": "x-lml/x-gps", ".rtf": "application/rtf", ".rtg": "application/metastream", ".rtx": "text/richtext", ".rv": "video/vnd.rn-realvideo", ".rwc": "application/x-rogerwilco", ".s3m": "audio/x-mod", ".s3z": "audio/x-mod", ".sca": "application/x-supercard", ".scd": "application/x-msschedule", ".sct": "text/scriptlet", ".sdf": "application/e-score", ".sea": "application/x-stuffit", ".setpay": "application/set-payment-initiation", ".setreg": "application/set-registration-initiation", ".sgm": "text/x-sgml", ".sgml": "text/x-sgml", ".sh": "application/x-sh", ".shar": "application/x-shar", ".shtml": "magnus-internal/parsed-html", ".shw": "application/presentations", ".si6": "image/si6", ".si7": "image/vnd.stiwap.sis", ".si9": "image/vnd.lgtwap.sis", ".sis": "application/vnd.symbian.install", ".sit": "application/x-stuffit", ".skd": "application/x-Koan", ".skm": "application/x-Koan", ".skp": "application/x-Koan", ".skt": "application/x-Koan", ".slc": "application/x-salsa", ".smd": "audio/x-smd", ".smi": "application/smil", ".smil": "application/smil", ".smp": "application/studiom", ".smz": "audio/x-smd", ".snd": "audio/basic", ".spc": "application/x-pkcs7-certificates", ".spl": "application/futuresplash", ".spr": "application/x-sprite", ".sprite": "application/x-sprite", ".sdp": "application/sdp", ".spt": "application/x-spt", ".src": "application/x-wais-source", ".sst": "application/vnd.ms-pkicertstore", ".stk": "application/hyperstudio", ".stl": "application/vnd.ms-pkistl", ".stm": "text/html", ".svg": "image/svg+xml", ".sv4cpio": "application/x-sv4cpio", ".sv4crc": "application/x-sv4crc", ".svf": "image/vnd", ".svg": "image/svg+xml", ".svh": "image/svh", ".svr": "x-world/x-svr", ".swf": "application/x-shockwave-flash", ".swfl": "application/x-shockwave-flash", ".t": "application/x-troff", ".tad": "application/octet-stream", ".talk": "text/x-speech", ".tar": "application/x-tar", ".taz": "application/x-tar", ".tbp": "application/x-timbuktu", ".tbt": "application/x-timbuktu", ".tcl": "application/x-tcl", ".tex": "application/x-tex", ".texi": "application/x-texinfo", ".texinfo": "application/x-texinfo", ".tgz": "application/x-compressed", ".thm": "application/vnd.eri.thm", ".tif": "image/tiff", ".tiff": "image/tiff", ".tki": "application/x-tkined", ".tkined": "application/x-tkined", ".toc": "application/toc", ".toy": "image/toy", ".tr": "application/x-troff", ".trk": "x-lml/x-gps", ".trm": "application/x-msterminal", ".tsi": "audio/tsplayer", ".tsp": "application/dsptype", ".tsv": "text/tab-separated-values", ".ttf": "application/octet-stream", ".ttz": "application/t-time", ".txt": "text/plain", ".uls": "text/iuls", ".ult": "audio/x-mod", ".ustar": "application/x-ustar", ".uu": "application/x-uuencode", ".uue": "application/x-uuencode", ".vcd": "application/x-cdlink", ".vcf": "text/x-vcard", ".vdo": "video/vdo", ".vib": "audio/vib", ".viv": "video/vivo", ".vivo": "video/vivo", ".vmd": "application/vocaltec-media-desc", ".vmf": "application/vocaltec-media-file", ".vmi": "application/x-dreamcast-vms-info", ".vms": "application/x-dreamcast-vms", ".vox": "audio/voxware", ".vqe": "audio/x-twinvq-plugin", ".vqf": "audio/x-twinvq", ".vql": "audio/x-twinvq", ".vre": "x-world/x-vream", ".vrml": "x-world/x-vrml", ".vrt": "x-world/x-vrt", ".vrw": "x-world/x-vream", ".vts": "workbook/formulaone", ".wav": "audio/x-wav", ".wax": "audio/x-ms-wax", ".wbmp": "image/vnd.wap.wbmp", ".wcm": "application/vnd.ms-works", ".wdb": "application/vnd.ms-works", ".web": "application/vnd.xara", ".wi": "image/wavelet", ".wis": "application/x-InstallShield", ".wks": "application/vnd.ms-works", ".wm": "video/x-ms-wm", ".wma": "audio/x-ms-wma", ".wmd": "application/x-ms-wmd", ".wmf": "application/x-msmetafile", ".wml": "text/vnd.wap.wml", ".wmlc": "application/vnd.wap.wmlc", ".wmls": "text/vnd.wap.wmlscript", ".wmlsc": "application/vnd.wap.wmlscriptc", ".wmlscript": "text/vnd.wap.wmlscript", ".wmv": "audio/x-ms-wmv", ".wmx": "video/x-ms-wmx", ".wmz": "application/x-ms-wmz", ".wpng": "image/x-up-wpng", ".wps": "application/vnd.ms-works", ".wpt": "x-lml/x-gps", ".wri": "application/x-mswrite", ".wrl": "x-world/x-vrml", ".wrz": "x-world/x-vrml", ".ws": "text/vnd.wap.wmlscript", ".wsc": "application/vnd.wap.wmlscriptc", ".wv": "video/wavelet", ".wvx": "video/x-ms-wvx", ".wxl": "application/x-wxl", ".x-gzip": "application/x-gzip", ".xaf": "x-world/x-vrml", ".xar": "application/vnd.xara", ".xbm": "image/x-xbitmap", ".xdm": "application/x-xdma", ".xdma": "application/x-xdma", ".xdw": "application/vnd.fujixerox.docuworks", ".xht": "application/xhtml+xml", ".xhtm": "application/xhtml+xml", ".xhtml": "application/xhtml+xml", ".xla": "application/vnd.ms-excel", ".xlc": "application/vnd.ms-excel", ".xll": "application/x-excel", ".xlm": "application/vnd.ms-excel", ".xls": "application/vnd.ms-excel", ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ".xlt": "application/vnd.ms-excel", ".xlw": "application/vnd.ms-excel", ".xm": "audio/x-mod", ".xml": "text/plain", ".xml": "application/xml", ".xmz": "audio/x-mod", ".xof": "x-world/x-vrml", ".xpi": "application/x-xpinstall", ".xpm": "image/x-xpixmap", ".xsit": "text/xml", ".xsl": "text/xml", ".xul": "text/xul", ".xwd": "image/x-xwindowdump", ".xyz": "chemical/x-pdb", ".yz1": "application/x-yz1", ".z": "application/x-compress", ".zac": "application/x-zaurus-zac", ".zip": "application/zip", ".json": "application/json" }
-
区分GET-POST请求
通过HTTP模块
http.IncomingMessage
类的.method
属性const http = require('http'); http.createServer(function (req, res) { res.writeHead(200, { "Content-Type" : 'text/plan; charset=utf8;' }) if(req.method.toLowerCase() === 'get'){ res.end('get请求'); }else if(req.method.toLowerCase() === 'post'){ res.end('post请求'); } }).listen(3000)
-
动态网站
<!-- index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="./info.html" method="post"> <input type="text" name="userName"> <input type="submit" value="查询"> </form> </body> </html>
<!-- info.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>名字:!!!name!!!</p> <p>性别:!!!sex!!!</p> <p>年龄:!!!age!!!</p> </body> </html>
const http = require('http'); const path = require('path'); const fs = require('fs'); const url = require('url'); const queryString = require('querystring'); let persons = { 'zhangsan': { name: '张三', age: 18, sex: '男' }, "lisi": { name: '李四', age: 22, sex: '女' } } http.createServer(function (req, res) { if(req.url.startsWith('/index') && req.method.toLowerCase() === 'get'){ let obj = url.parse(req.url); let filePath = path.join(__dirname, obj.pathname); fs.readFile(filePath, 'utf8', function (err, data) { if(err){ res.writeHead(404, { "Content-Type" : "text/plain; charset=utf-8;" }) res.end('Page Not Found'); } res.writeHead(200, { "Content-Type" : "text/html; charset=utf-8;" }) res.end(data); }) } else if(req.url.startsWith('/info') && req.method.toLowerCase() === 'post'){ let params = ''; req.on('data', function (chunk) { params += chunk; }) req.on('end', function () { let obj = queryString.parse(params); let per = persons[obj.userName]; let filePath = path.join(__dirname, req.url); fs.readFile(filePath, 'utf8', function (err, data) { if(err){ res.writeHead(404, { "Content-Type" : "text/plain; charset=utf-8;" }) res.end('Page Not Found'); } data = data.replace('!!!name!!!', per.name); data = data.replace('!!!age!!!', per.age); data = data.replace('!!!sex!!!', per.sex); res.end(data); }) }) } }).listen(3000);
-
模板引擎(对动态网站优化)
使用
art-template
模板<!-- index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="./info.html" method="post"> <input type="text" name="userName"> <input type="submit" value="查询"> </form> </body> </html>
<!-- info.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>名字:{{name}}</p> <p>性别:{{sex}}</p> <p>年龄:{{age}}</p> </body> </html>
//23.js const http = require('http'); const path = require('path'); const fs = require('fs'); const url = require('url'); const queryString = require('querystring'); const template = require('art-template'); let persons = { 'zhangsan': { name: '张三', age: 18, sex: '男' }, "lisi": { name: '李四', age: 22, sex: '女' } } http.createServer(function (req, res) { if(req.url.startsWith('/index') && req.method.toLowerCase() === 'get'){ let obj = url.parse(req.url); let filePath = path.join(__dirname, obj.pathname); fs.readFile(filePath, 'utf8', function (err, data) { if(err){ res.writeHead(404, { "Content-Type" : "text/plain; charset=utf-8;" }) res.end('Page Not Found'); } res.writeHead(200, { "Content-Type" : "text/html; charset=utf-8;" }) res.end(data); }) } else if(req.url.startsWith('/info') && req.method.toLowerCase() === 'post'){ let params = ''; req.on('data', function (chunk) { params += chunk; }) req.on('end', function () { let obj = queryString.parse(params); let per = persons[obj.userName]; let filePath = path.join(__dirname, req.url); let html = template(filePath, per); res.writeHead(200, { "Content-Type" : "text/html; charset=utf-8;" }) res.end(html); }) } }).listen(3000);
URL
-
如何拿到Get请求传递过来的参数
使用
url
模块url.format(urlObject)
将路径转换为对象url.parse(urlString[, parseQueryString[, slachesDenoteHost]])
将对象转换为路径const http = require('http'); const url = require('url'); http.createServer(function (req, res) { let obj = url.parse(req.url, true); res.end(obj.query.name + '-----' + obj.query.age); }).listen(3000)
querystring
-
如果拿到post请求传递过来的参数
使用
querystring
模块querystring.parse(str[, sep[, eq[, options]]])
将参数转换为对象querystring.stringify(obj[, sep[, eq[, options]]])
将对象转换为参数const http = require('http'); const querystring = require('querystring'); http.createServer(function (req, res) { // 在NodeJS中,post请求的参数我们不能一次性拿到,需要分批获取 let params = ''; req.on('data', function (chunk) { params += chunk; }) req.on('end', function () { let obj = querystring.parse(params); res.end(obj.userName + '----' + obj.password); }) }).listen(3000)
Node模块原理
浏览器事件环
-
js是单线程的
js中的代码都是串行的,前面没有执行的代码后面不能执行
-
执行顺序
程序运行会从上至下一次执行所有的同步代码
在执行的过程中如果遇到异步代码会将异步代码放到事件循环中
当所有同步代码都执行完毕后,js会不断检测事件循环中的异步代码是否满足条件
一旦满足条件就执行满足条件的异步代码
-
宏任务和微任务
在js的异步代码中又区分"宏任务(MacroTask)“和"微任务(MicroTask)”
宏任务:宏/大的意思,可以理解为比较费时比较慢的任务
微任务:微/小的意思,可以理解为相对没有那么费时没有那么慢的任务
-
常见的宏任务和微任务
MarcroTask: setTimeout、setInterval、setImmediate(独有)…
MicroTask: Promise、MutationObserver、process.nextTick(node独有)…
注意点:
- 所有的宏任务和微任务都会放到自己的执行队列中,也就是有一个宏任务队列和一个微任务队列
- 所有放到队列中的任务都采用"先进先出原则",也就是多个任务同时满足条件,那么会先执行先放进去的
-
完整执行顺序
从上至下执行所有同步代码
在执行过程中遇到宏任务就放到宏任务队列中,遇到微任务就放到微任务队列中
当所有同步代码执行完毕之后,就执行微任务队列中满足需求所有回调
当微任务队列所有满足需求回调执行完毕之后,就执行宏任务队列中满足需求所有回调
…
注意点:
- 每执行完一个宏任务都会立刻检查微任务队列有没有被清空,如果没有就立刻清空
Node事件环
-
概述
和浏览器中一样NodeJS中也有事件环(Event Loop)
但是由于执行代码的宿主环境和应用场景不同
所以两者的事件环也有所不同
-
NodeJS事件环和浏览器事件环区别
-
任务队列个数不同
浏览器事件环有2个事件队列(宏任务和微任务)
NodeJS事件环有六个事件队列
-
微任务队列不同
浏览器事件环中有专门存储微任务的队列
NodeJS事件环中没有专门存储微任务的队列
-
微任务执行时机不同
浏览器中事件环中每执行完一个宏任务都会去清空微任务队列
NodeJS事件环中只有同步代码执行完毕和其它队列之间切换的时候回去清空微任务队列
-
微任务优先级不同
浏览器事件环中如果有多个微任务同时满足执行条件,采用先进先出
NodeJS事件环中如果有多个微任务同时满足执行条件,会按照优先级执行
-
NodeJS中的任务队列
┌───────────────────────┐ ┌> │timers │执行setTimeout() 和 setInterval()中到期的callback │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │pending callbacks│执行系统操作的回调, 如:tcp, udp通信的错误callback │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │idle, prepare │只在内部使用 │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │poll │执行与I/O相关的回调 │ (除了close回调、定时器回调和setImmediate()之外,几乎所有回调都执行); │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │check │执行setImmediate的callback │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ └─┤close callbacks │执行close事件的callback,例如socket.on("close",func) └───────────────────────┘ ┌───────────────────────┐ ┌> │timers │执行setTimeout() 和 setInterval()中到期的callback │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │poll │执行与I/O相关的回调 │ (除了close回调、定时器回调和setImmediate()之外,几乎所有回调都执行); │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ └─┤check │执行setImmediate的callback └───────────────────────┘
注意点:
- 和浏览器不同的是没有宏任务队列和微任务队列的概念
- 宏任务被放到了不同的队列中,但是没有队列是存放微任务的队列
- 微任务会在执行完同步代码和队列切换的时候执行
什么时候切换队列?
当队列为空(已经执行完毕或者没有满足条件回到)
或者执行的回调函数数量到达系统设定的阈值时任务队列就会切换
注意点:
- 在NodeJS中process.nextTick微任务的优先级高于Promise.resolve微任务
┌───────────────────────┐ │ 同步代码 └──────────┬────────────┘ │ │ <---- 满足条件微任务代码 │ ┌──────────┴────────────┐ ┌> │timers │执行setTimeout() 和 setInterval()中到期的callback │ └──────────┬────────────┘ │ │ │ │ <---- 满足条件微任务代码 │ │ │ ┌──────────┴────────────┐ │ │poll │执行与I/O相关的回调 │ │ (除了close回调、定时器回调和setImmediate()之外,几乎所有回调都执行); │ └──────────┬────────────┘ │ │ │ │ <---- 满足条件微任务代码 │ │ │ ┌──────────┴────────────┐ └─┤check │执行setImmediate的callback └───────────────────────┘
注意点:
- 执行完poll, 会查看check队列是否有内容, 有就切换到check
- 如果check队列没有内容, 就会查看timers是否有内容, 有就切换到timers
- 如果check队列和timers队列都没有内容, 为了避免资源浪费就会阻塞在poll
笔记摘抄于:https://it666.com/
-