Node基础

71 阅读8分钟

1、初识 Nodejs

官网传送门

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine

Node.js® 是一个基于 Chrome V8 引擎 的 JavaScript 运行时环境

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 指向的对象。
  • 默认情况下,exportsmodule.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\tools
  • C:\Users\bruce\node_modules\tools
  • C:\Users\node_modules\tools
  • C:\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