Node.js
Node.js是一个基于Chrome V8引擎的JavaScript运行环境
官方地址:https://nodejs.org/zh-cn/
- 浏览器是JavaScript的前端运行环境
- Node.js是JavaScript的后端运行环境
- Node.js中无法调用DOM和BOM等浏览器内置API
主要学习:JavaScript Node.js
内置API模块(fs
、path
、http
等) 第三方API模块(express
、mysql
等)
环境安装:官网下载安装(推荐LTS版本)
查看版本:node-v
终端命令
执行代码:node app.js
fs文件系统模块
fs模块是Node.js官方提供的、用来操作文件的模块,它提供了一系列的方法和属性,用来满足用户对文件的需求。
- fs.readFile()方法:用来读取指定文件中的内容。
- fs.writeFile()方法:用来向指定文件中写入内容。
在JavaScript代码中,使用fs模块之前,需要先导入它:
代码语言:javascript复制const fs = require('fs')
读取指定文件中的内容
代码语言:javascript复制fs.readFile('path','options',callback)
- 参数1:必选参数,字符串,表示文件的路径.
- 参数2:可选参数,表示什么编码格式读取文件,通常为(utf8)
- 参数3:必选参数,文件读取完成后,通过回调函数拿到读取的结果。
示例:
代码语言:javascript复制fs.readFile('./files/12.txt','utf8',function(err,dataStr){
//2.1打印失败的结果
//如果读取成功,则err的值为null
//如果读取失败,则err的值为错误对象,dataStr的值为underfined
console.log(err);
console.log('--------');
//2.2打印成功的结果
console.log(dataStr);
})
可以判断err
对象是否为null
,从而知晓文件读取的结果:
const fs = require('fs');
fs.readFile('./files/111.txt', 'utf-8', function (err, dataStr) {
if (err) {
return console.log('读取文件失败' err.message); //读取文件失败ENOENT: no such file or directory, open 'E:WebNode.jsDay1files111.txt'
}
console.log('读取文件成功,结果是' dataStr); //读取文件成功,结果是111
});
向指定文件中写入内容
代码语言:javascript复制fs.writeFile('file','data','options',callback)
- 参数1:必选参数,需要指定一个文件路径的字符串,表示文件的存放路径
- 参数2:必选参数,要写入的内容
- 参数3:可选参数,写入文件格式,默认是utf8
- 参数4:必选参数,文件写入完成后的回调函数。
示例(判断是否写入成功):
代码语言:javascript复制//1.导入fs文件系统模块
const fs=require('fs')
fs.writeFile('./files/3.txt','ok123',function(err){
//如果文件写入成功,则err的值等于null
//如果文件写入失败,则err的值等于一个错误对象
// console.log(err);
if(err){
return console.log('文件写入失败!' err.message);
}
console.log('文件写入成功');
})
练习:考试成绩整理
原数据:
代码语言:javascript复制小红=99 小白=100 小黄=70 小黑=90
整理后:
代码语言:javascript复制小红:99
小白:100
小黄:70
小黑:90
代码:
代码语言:javascript复制const fs=require('fs')
//调用fs.readFile()读取文件内容
fs.readFile('./files/成绩.txt','utf-8',function(err,dataStr){
//判断是否读取成功
if(err){
return console.log('读取文件失败' err.message);
}
// console.log('读取成功' dataStr);
//4.1先把成绩的数据,按照空格进行分隔
const arrOld=dataStr.split(' ')
// console.log(arrOld);
// 4.2循环分割后的数组,对每一项数据,进行字符串的替换操作
const arrNew=[]
arrOld.forEach(item=>{
arrNew.push(item.replace('=',':'))
})
// 4.3把新数组中的每一项,进行合并,得到一个新的字符串
const newStr= arrNew.join('rn')
console.log(newStr);
//5.调用fs.writeFile()方法,把处理完的成绩,写入到新文件中
fs.writeFile('./files/成绩-ok.txt',newStr,function(err){
if(err){
return console.log('写入文件失败' err.message);
}
console.log('成绩写入成功');
})
})
fs模块的路径动态拼接
在使用fs模块操作文件时,直接提供完整的路径,不要提供./和../开头的相对路径,防止动态路径拼接出错。
代码语言:javascript复制// __dirname表示当前文件所处的目录
fs.readFile(__dirname '/files/1.txt','utf-8',function(err,dataStr){
if(err){
return console.log('读取文件失败' err.message);
}
console.log('读取文件成功' dataStr);
})
path路径模块
path 模块是 Node.js 官方提供的、用来处理路径的模块。它提供了一系列的方法和属性,用来满足用户对路径的处理 需求。
path.join()
方法:用来将多个路径拼接成一个完整的路径字符串。path.basename()
方法:用来从路径字符串中,将文件名解析出来。
使用path模块之前,先导入:
代码语言:javascript复制const path = require('path')
路径拼接
代码语言:javascript复制path.join([...paths])
...paths<string>
路径片段的序列- 返回值:
<string>
示例:
代码语言:javascript复制const pathStr = path.join('/a', '/b/c', '../', './d', 'e');
console.log(pathStr);//输出内容:abde
const pathStr1 = path.join(__dirname,'./files/1.txt');
console.log(pathStr1);//输出:当前文件所处目录/files/1.txt
注意:但凡涉及到路径拼接的操作,都要使用path.join()
方法进行处理,不要直接使用
进行字符串拼接。
获取路径中的文件名
代码语言:javascript复制path.basename(path,ext)
此方法可以获取到路径中的最后一部分。
path
:必选参数,表示一个路径的字符串ext
:可选参数,表示文件扩展名- 返回:表示路径中的最后一部分
示例:
代码语言:javascript复制//文件存放的路径
const fpath = 'a/b/c/index.html';
//文件名 扩展名
const fullName = path.basename(fpath);
console.log(fullName); //输出 index.html
//文件名
const nameWithoutExit = path.basename(fpath, '.html');
console.log(nameWithoutExit); //输出 index
获取路径中的文件扩展名
代码语言:javascript复制path.extname(path)
- path:必选参数,路径的字符串
- 返回:返回得到文件的扩展名字符串
示例:
代码语言:javascript复制//文件存放的路径
const fpath = 'a/b/c/index.html';
const kzm = path.extname(fpath);
console.log(kzm); //输出 html
http模块
在网络节点中,负责消费资源的电脑,叫做客户端;负责对外提供网络资源的电脑,叫做服务器。
http
模块是 Node.js
官方提供的、用来创建 web 服务器的模块。通过 http
模块提供的 http.createServer()
方法,就 能方便的把一台普通的电脑,变成一台 Web 服务器,从而对外提供 Web 资源服务。
创建最基本的web服务器
1.导入htpp模块
代码语言:javascript复制const http = require('http')
2.创建web服务器实例
代码语言:javascript复制const server = http.createServer()
3.为服务器实例绑定request
事件
绑定request
事件,即可监听客户端发送过来的网络请求。
server.on('request',function(req,res){
console.log('Someone visit our web server');
})
4.启动服务器
调用服务器实例的.listen()方法,即可启动当前的web服务器实例.
代码语言:javascript复制server.listen(80,function(){
console.log('server running at http://127.0.0.1:80');
})
req请求对象
只要服务器接收到了客户端的请求,就会调用通过server.on()
为服务器绑定的request
事件处理函数。
如果想在事件处理函数中,访问与客户端相关的数据或属性,可以使用如下方式:
代码语言:javascript复制server.on('request',(req)=>{
//req是请求对象,它包含了与客户端相关的数据和属性
//req.url是客户端请求的URL地址
//req.method是客户端的method请求类型
const str = 'Your request url is $(req.url),and request method is ${req.method}'
console.log(str)
})
解决中午乱码问题
当调用 res.end()
方法,向客户端发送中文内容的时候,会出现乱码问题,此时,需要手动设置内容的编码格式:
server.on('request', (req,res)=> {
//定义一个字符串,包含中文内容
const str=`你请求的URL地址是 ${req.url},请求的method类似为 ${req.method}`
//调用res.setHeader()方法,设置响应头 Content-Type的值为text/html;charset=utf-8
res.setHeader('Content-Type','text/html;charset=utf-8')
res.end(str)
})
根据不同的url响应不同的html内容
代码语言:javascript复制const http=require('http')
const server=http.createServer()
server.on('request',(req,res)=>{
//1.获取请求的url地址
const url=req.url
//2.设置默认的响应内容为404
let content='404 Not found'
//3.判断用户请求的是否为/或者/index.html页面 首页
if(url==='/'||url==='/index.html'){
content='<h1>首页</h1>'
//4.判断用户请求是否为/about.html页面
}else if(url==='/about.html'){
content='<h1>关于</h1>'
}
//5.设置响应头,防止中文乱码
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');
})
Node.js中的模块化
Node.js中根据模块来源不同,将模块分为3个大类:
- 内置模块:内置模块是由
Node.js
官方提供的,例如fs
、path
、http
等 - 自定义模块:用户创建的每个
.js
文件,都是自定义模块 - 第三方模块:由第三方开发出来的模块,并非官方提供的内置模块,也不是用户创建的自定义模块,使用前需要先下载。
加载模块
使用强大的require()
方法,可以加载需要的内置模块、用户自定义模块、第三方模块进行使用。
//1.加载内置的fs模块
const fs = require('fs')
//2,加载用户的自定义模块
const custom = require('./custom.js')
//3.加载第三方模块
const moment = require('moment')
注意:使用require()
方法加载其他模块时,会执行被加载模块中的代码。
模块作用域
和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域。
代码语言:javascript复制//01模块
//在模块作用域中定义常量username
const username = '张三';
//在模块作用域中定义函数sayHello
function sayHello() {
console.log('大家好,我是' username);
}
代码语言:javascript复制//02.js
const custom = require('./01');
//输出空对象,在02.js模块中,无法访问到01模块中的私有成员
console.log(custom);
好处:
防止了全局变量污染问题。
向外共享模块作用域中的成员
1.module
对象
在每个.js自定义模块中都有一个module
对象,它里面存储了和当前模块有关的信息:
2.module.exports
对象
在自定义模块中,可以使用 module.exports
对象,将模块内的成员共享出去,供外界使用。 外界用 require()
方法导入自定义模块时,得到的就是 module.exports
所指向的对象。
3.共享成员时的注意点
使用 require()
方法导入模块时,导入的结果,永远以 module.exports
指向的对象为准
4.exports
对象
由于 module.exports
单词写起来比较复杂,为了简化向外共享成员的代码,Node 提供了 exports
对象。
默认情况 下,exports
和 module.exports
指向同一个对象。
最终共享的结果,还是以 module.exports
指向的对象为准。
时刻谨记,require()
模块时,得到的永远是 module.exports
指向的对象:
注意:为了防止混乱,不要在同一个模块中同时使用exports
和module.exports
模块化规范
Node.js
遵循了 CommonJS
模块化规范,CommonJS
规定了模块的特性和各模块之间如何相互依赖。
CommonJS
规定:
- 每个模块内部,
module
变量代表当前模块。 module
变量是一个对象,它的exports
属性(即module.exports
)是对外的接口。- 加载某个模块,其实是加载该模块的
module.exports
属性。require()
方法用于加载模块。
npm与包
从 https://www.npmjs.com/ 网站上搜索自己所需要的包
从 https://registry.npmjs.org/ 服务器上下载自己需要的包
1.在项目中安装包的命令
代码语言:javascript复制npm intsall 包的完整名称
2.卸载包的命令
代码语言:javascript复制npm uninstall 包的完整名称
devDependencies节点
devDependencies
节点:包只在项目开发阶段会用到,在项目上线之后不会用到dependencies
节点:包在开发和项目上线之后都需要用到
//安装指定的包,并记录到devDependencies节点中
npm i 包名 -D
npm install 包名 --save-dev
解决下包慢
代码语言:javascript复制# 查看当前的下包镜像源
npm config get registry
# 将下包镜像源切换为淘宝镜像源
npm config set registry=https://registry.npm.taobao.org/
nrm
安装nrm小工具,利用nrm提供的终端命令,可以快速查看和切换下包的镜像源。
代码语言:javascript复制# 安装
npm i nrg -g
# 查看
nrm ls
# 切换
nrm use taobao
包的分类
1.项目包
被安装到项目的 node_modules 目录中的包,都是项目包。
项目包又分两类:
- 开发依赖包:被记录在devDependencies节点,只在开发期间用到
- 核心依赖包:被记录到dependencies节点,在开发期间和项目上线都会用到
npm i 包名 -D #开发依赖包
npm i 包名 -S #核心依赖包
2.全局包
在执行 npm install 命令时,如果提供了 -g
参数,则会把包安装为全局包。
全局包会被安装到 C:Users用户目录AppDataRoamingnpmnode_modules
目录下。
npm i 包名 -g #全局安装指定的包
npm uninstall 包名 -g #卸载全局安装的包
注意:
- 只要工具性质的包,才有全局安装的必要性,因为它们提供了好用的终端命令。
- 判断某个包是否需要全局安装后才能使用,可以参考相关官方文档提供的使用说明。
模块的加载机制
优先从缓存中加载
模块在第一次加载后会被缓存。 这也意味着多次调用 require() 不会导致模块的代码被执行多次。
注意:不论是内置模块、用户自定义模块、还是第三方模块,它们都会优先从缓存中加载,从而提高模块的加载效率。
内置模块的加载机制
内置模块是由 Node.js
官方提供的模块,内置模块的加载优先级最高。
例如,require('fs')
始终返回内置的 fs
模块,即使在 node_modules
目录下有名字相同的包也叫做 fs
。
自定义模块的加载机
使用 require()
加载自定义模块时,必须指定以 ./ 或 ../
开头的路径标识符。
在加载自定义模块时,如果没有指定 ./
或 ../
这样的路径标识符,则 node
会把它当作内置模块或第三方模块进行加载。
同时,在使用 require()
导入自定义模块时,如果省略了文件的扩展名,则 Node.js 会按顺序分别尝试加载以下的文件:
- 按照确切的文件名进行加载
- 补全 .js 扩展名进行加载
- 补全 .json 扩展名进行加载
- 补全 .node 扩展名进行加载
- 加载失败,终端报错
第三方模块的加载机制
如果传递给 require()
的模块标识符不是一个内置模块,也没有以 ‘./’ 或 ‘../’ 开头,则 Node.js
会从当前模块的父 目录开始,尝试从 /node_modules
文件夹中加载第三方模块。
如果没有找到对应的第三方模块,则移动到再上一层父目录中,进行加载,直到文件系统的根目录。
例如,假设在 'C:Usersitheimaprojectfoo.js
' 文件里调用了 require('tools')
,则 Node.js
会按以下顺序查找:
- C:Usersitheimaprojectnode_modulestools
- C:Usersitheimanode_modulestools
- C:Usersnode_modulestools
- C:node_modulestools
目录作为模块
当把目录作为模块标识符,传递给 require()
进行加载的时候,有三种加载方式:
- 在被加载的目录下查找一个叫做
package.json
的文件,并寻找main
属性,作为require()
加载的入口 - 如果目录里没有
package.json
文件,或者main
入口不存在或无法解析,则Node.js
将会试图加载目录下的index.js
文件。 - 如果以上两步都失败了,则
Node.js
会在终端打印错误消息,报告模块的缺失:Error: Cannot find module 'xxx‘