1、初识 Nodejs
Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine
Node.js® 是一个基于 Chrome V8 引擎 的 JavaScript 运行时环境
- 基于 Express 框架 (opens new window),可以快速构建 Web 应用
- 基于 Electron 框架 (opens new window),可以构建跨平台的桌面应用
- 基于 restify 框架 (opens new window),可以快速构建 API 接口项目
- 读写和操作数据库、创建实用的命令行工具辅助前端开发、etc…
2、fs 文件系统模块
读取文件
//1.导入 fs 模块
const fs = require('fs')
//2.调用 fs.readFile() 方法读取文件
// 参数1:读取文件的存放路径
// 参数2:读取文件时采用的编码格式,一般默认指定 utf8
// 参数3:回调函数,拿到读取失败和成功的结果 err dataStr
fs.readFile('./files/1.txt','utf8',function(err,dataStr){
//2.1 打印失败的结果
//如果读取成功,则err的值为null
//如果读取失败,则err的值为错误对象,dataStr的值为undefined
console.log(err);
console.log('---------');
//2.2 打印成功的结果
console.log(dataStr);
})
可以通过err是否为空来判断是否读取成功
写入文件
//1.导入fs文件系统模块
const fs = require('fs')
//2.调用fs.writeFile()方法,写入文件的内容
// 参数1:表示文件的存放路径
// 参数2:表示要写入的内容
// 参数3:回调函数,(参数3之前还有个编码参数,默认utf8,一般不需要写)
fs.writeFile('M:/files/2.txt','abcd',function(err){
//2.1 如果文件写入成功,则err的值等于null
//2.2 如果文件写入失败,则err的值等于一个错误对象
console.log(err);
})
可以通过err是否为空来判断是否写入成功
路径动态拼接问题
在使用 fs 模块操作文件时,如果提供的操作路径是以
./或../开头的相对路径时,容易出现路径动态拼接错误的问题原因:代码在运行的时候,会以执行 node 命令时所处的目录,动态拼接出被操作文件的完整路径
解决方案:在使用 fs 模块操作文件时,直接提供完整的路径,从而防止路径动态拼接的问题,但是也会造成移植性非常差,不利于维护的问题
所以可以使用
__dirname获取当前文件所处的绝对路径
fs.readFile(__dirname+'/files/1.txt','utf8',function(err,dataStr){
...
})
3、path路径模块
path 模块是 Node.js 官方提供的、用来处理路径的模块。它提供了一系列的方法和属性,用来满足用户对路径的处理需求。
路径拼接 path.join()
注意:今后凡是涉及到路径拼接的操作,都要使用path.join()方法进行处理。
const path = require('path')
const fs = require('fs')
//注意: ../会抵消前面的路径
// ./ 会被忽略
const pathStr = path.join('/a','/b/c','../','./d','e')
console.log(pathStr); // \a\b\d\e
fs.readFile(path.join(__dirname,'/files/1.txt'),'utf8',function(err,dataStr){
if (err) {
return console.log(err.message)
}
console.log(dataStr)
})
获取路径中文件名 path.basename()
使用 path.basename() 方法,可以获取路径中的最后一部分,常通过该方法获取路径中的文件名
path.basename(path[, ext])
- path: 文件路径(必须参数)
- ext: 移除文件扩展名(可选参数)
const path = require('path')
// 定义文件的存放路径
const fpath = '/a/b/c/index.html'
const fullName = path.basename(fpath)
console.log(fullName) // index.html
const nameWithoutExt = path.basename(fpath, '.html')
console.log(nameWithoutExt) // index
获取路径中文件扩展名 path.extname()
const path = require('path')
// 这是文件的存放路径
const fpath = '/a/b/c/index.html'
const fext = path.extname(fpath)
console.log(fext) // .html
4、http 模块
http 模块是 Node.js 官方提供的、用来创建 web 服务器的模块。
创建基本 Web 服务器
//1. 导入http模块
const http = require('http')
//2. 创建web服务器实例
const server = http.createServer();
//3. 为服务器实例绑定request事件,监听客户端的请求
// req是请求对象
// res是响应对象
server.on('request',(req,res)=>{
//req.url 是客户端请求的url地址
const url = req.url
//req.method 是客户端请求的method类型
const method = req.method
const str = `Your request url is ${url},and requset method is ${method}`
// 设置 Content-Type 响应头,解决中文乱码的问题
res.setHeader('Content-Type', 'text/html; charset=utf-8')
// 调用res.end() 方法,向客户端响应一些内容
res.end(str);
})
//4.启动服务器
server.listen(80,()=>{
console.log('server running at http://127.0.0.1');
})
实现简单的不同路由响应不同数据
const http = require('http')
const server = http.createServer()
server.on('request',(req,res)=>{
//1.获取请求的url地址
const url = req.url
//2.设置默认的响应内容为 404 Not found
let content = '404 Not found!'
//3.判断用户请求是否为 / 或 /index.html 首页
//4.判断用户请求的是否为 /about.html 关于页面
if(url==='/'||url==='/index.html'){
content = `<h1>首页</h1>`
}else if(url==='/about.html'){
content = `<h1>关于</h1>`
}
//5.设置 Content-Type 响应头,防止中文乱码
res.setHeader('Content-Type','text/html;charset=utf-8')
//6.使用res.end() 把内容响应给客户端
res.end(content)
})
server.listen(80,()=>{
console.log('server running at http://127.0.0.1');
})
实现clock时钟的web服务器
//1.1 导入 http 模块
const http = require('http')
//1.2 导入 fs 模块
const fs = require('fs')
//1.3 导入 path 模块
const path = require('path')
//2.1 创建web服务器
const server = http.createServer()
//2.2 监听web服务器的 request 事件
server.on('request',(req,res)=>{
//3.1 获取到客户端请求的URL地址
const url = req.url
//3.2 把请求的URL地址映射为具体文件的存放路径
// const fpath = path.join(__dirname,url);
/*** 将3.2的代码优化 */
// 5.1 预定义空白的文件存放路径
let fpath = '';
if(url==='/'){
//5.2 如果请求的路径为/根路径,则手动指定到首页
fpath = path.join(__dirname,'/clock/index.html');
}else{
fpath = path.join(__dirname,'/clock',url);
}
//4.1 根据“映射”过来的文件路径读取文件的内容
fs.readFile(fpath,'utf8',(err,dataStr)=>{
//4.2 读取失败,向客户端响应固定的“错误消息”
if(err) return res.end("404 Not found!")
//4.3 读取成功,将读取成功的内容,响应给客户端
res.end(dataStr)
})
})
//2.3 启动web服务器
server.listen(80,()=>{
console.log('server running at http://127.0.0.1');
})
5、模块化
模块化概念
- 模块化是指解决一个复杂问题时,自顶向下逐层把系统划分为若干模块的过程,模块是可组合、分解和更换的单元。
- 模块化可提高代码的复用性和可维护性,实现按需加载。
- 模块化规范是对代码进行模块化拆分和组合时需要遵守的规则,如使用何种语法格式引用模块和向外暴露成员。
Node.js 中模块的分类
- 内置模块(内置模块是由Node.js官方提供的,例如fs、path、http等)
- 自定义模块(用户创建的每个 .js文件,都是自定义模块)
- 第三方模块(由第三方开发出来的模块,并非官网提供的内置模块,也不是用户创建的自定义模块,使用前需要先下载)
Node.js 中的模块作用域
- 和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域
- 防止全局变量污染
模块作用域的成员
- 自定义模块中都有一个
module对象,存储了和当前模块有关的信息 - 在自定义模块中,可以使用
module.exports对象,将模块内的成员共享出去,供外界使用。导入自定义模块时,得到的就是module.exports指向的对象。 - 默认情况下,
exports和module.exports指向同一个对象。最终共享的结果,以module.exports指向的对象为准。
CommonJS 模块化规范
- 每个模块内部,
module变量代表当前模块 module变量是一个对象,module.exports是对外的接口- 加载某个模块即加载该模块的
module.exports属性
模块加载机制
模块第一次加载后会被缓存,即多次调用 require() 不会导致模块的代码被执行多次,提高模块加载效率。
内置模块加载
内置模块加载优先级最高。
自定义模块加载
加载自定义模块时,路径要以 ./ 或 ../ 开头,否则会作为内置模块或第三方模块加载。
导入自定义模块时,若省略文件扩展名,则 Node.js 会按顺序尝试加载文件:
- 按确切的文件名加载
- 补全
.js扩展名加载 - 补全
.json扩展名加载 - 补全
.node扩展名加载 - 报错
格式化时间导入自定义模块实例
15.dateFormat.js:
//1.定义格式化时间的方法
function dateFormat(dtStr){
const dt = new Date(dtStr)
const y = dt.getFullYear()
const m = padZero(dt.getMonth()+1)
const d = padZero(dt.getDate())
const hh = padZero(dt.getHours())
const mm = padZero(dt.getMinutes())
const ss = padZero(dt.getSeconds())
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
}
//定义补零的函数
function padZero(n){
return n > 9 ? n : '0' + n
}
//导出共享dateFormat函数
module.exports = {
dateFormat
}
16.test.js:
//导入自定义的格式化时间的模块
const TIME = require('./15.dateFormat');
//调用方法,进行时间的格式化
const dt = new Date();
console.log(dt);//2022-06-22T02:12:14.595Z
const newTime = TIME.dateFormat(dt);
console.log(newTime);//2022-06-22 10:13:22
第三方模块加载
- 若导入第三方模块, Node.js 会从当前模块的父目录开始,尝试从
/node_modules文件夹中加载第三方模块。 - 如果没有找到对应的第三方模块,则移动到再上一层父目录中,进行加载,直到文件系统的根目录。
例如,假设在 C:\Users\bruce\project\foo.js 文件里调用了 require('tools'),则 Node.js 会按以下顺序查找:
C:\Users\bruce\project\node_modules\toolsC:\Users\bruce\node_modules\toolsC:\Users\node_modules\toolsC:\node_modules\tools
目录作为模块加载
当把目录作为模块标识符进行加载的时候,有三种加载方式:
- 在被加载的目录下查找
package.json的文件,并寻找main属性,作为require()加载的入口 - 如果没有
package.json文件,或者main入口不存在或无法解析,则 Node.js 将会试图加载目录下的index.js文件。 - 若失败则报错
npm包
i5ting_toc是一个可以把md文档转换为html页面的小工具,使用步骤:
#将i5ting_toc 安装为全局包
npm install i5ting_toc -g
# 调用 i5ting_toc,轻松实现md转html的功能
i5ting_toc -f 要转换的md文件 -o