Node.js学习分享(上)

Node.js

fs文件系统模块

  • fs模块是Node.js官方提供的、用来操作文件的模块。它提供了一系列的方法和属性,用来满足用户对文件的操作要求
  1. fs.readFile()方法,用来读取指定文件中的内容
  2. fs.writeFile()方法,用来向指定的文件中写入内容
  • 使用fs模块前需要导入fs模块
js 复制代码
const fs = require('fs')

fs.readFile()

  • 语法格式:
    fs.readFile(path[,options], callback)
  • 参数说明:
    • path:必选参数,字符串,表示文件的路径
    • options:可选参数,表示以什么编码格式来读取文件
    • callback:必选参数,文件读取完成后,通过回调函数拿到读取的结果
      如果读取失败:
      err的值为错误对象
      data的值为undefined

fs.writeFile()

  • 语法格式:
    fs.writeFile(path, data[,options], callback)
  • 参数说明:
    • path:必选参数,字符串,表示文件的路径
    • data:必选参数,表示要写入的内容
    • options:可选参数,表示以什么编码格式来写入文件,默认是utf8
    • callback:必选参数,文件写入完成后的回调函数
  • 需要注意的点:
    • 该方法只能用来创建文件不能用来创建文件夹(路径)
    • 重复调用该函数,新写入的内容会覆盖掉原来的内容
      路径动态拼接问题
  • 在使用fs模块操作文件时,如果提供的操作路径是以./或者.../开头的相对路径时,很容易出现路径动态拼接错误的问题
  • 原因:代码在运行的时候,会以执行node命令时所处的目录,动态拼接出被操作文件的完整路径
  • 解决方案:
    • 使用绝对路径代替相对路径(移植性差)
    • __dirname:表示当前文件所处的目录(推荐)

path路径模块

  • 用来处理路径的模块
  • 同样,使用前需要导入
js 复制代码
const path = require('path')

路径拼接

path.join()

  • 使用path.join()方法,可以把多个路径片段拼接为完整的路径字符串
  • 语法格式:
    path.join([...paths])
  • 参数解读:
    • ...paths:路径片段的序列
    • 返回值:
js 复制代码
const path = require('path')
// ../会抵消前面的路径
const pathStr = path.join('/a','/b/c','../','./d','e')

console.log(pathStr);
// /a/b/d/e

获取路径中的文件名

path.basename()的语法格式

  • 使用path.basename()方法,可以获取路径中的最后一部分,经常通过泽哥方法来获取路径中的文件名
  • 语法格式:
    path.basename(path[,ext])
  • 参数解读:
    • Path :必选参数,表示一个路径的字符串
    • Ext :可选参数,表示文件扩展名
    • 返回::表示路径中的最后一部分
  • 应用实例:
js 复制代码
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()的语法格式

  • 使用path.extname()方法,可以获得路径中的扩展名部分
  • 语法格式:
    path.extname(path)
  • 参数解读:
    • Path :必选参数,表示一个路径的字符串
    • 返回 :返回得到的扩展名字符串
js 复制代码
const path = require('path')
const fpath = '/a/b/c/index.html'

//获取文件扩展名
const extname = path.extname(fpath)
console.log(extname); //.html

http模块

  • 使用前同样需要导入
js 复制代码
const http = require('http')

服务器相关概念

IP地址

  • IP地址就是互联网上每台计算机的唯一地址,因此IP地址具有唯一性,只有在知道对方IP地址的前提下,才能与对应的电脑之间进行数据通信

域名和域名服务器

  • IP地址和域名是一一对应的关系,这份对应关系存放在一种叫做域名服务器(DNS)的电脑中,使用者只需通过好记的域名访问对应的服务器即可,对应的转换工作由域名服务器实现。因此,域名服务器就是提供IP地址和域名之间的转换服务的服务器

端口号

  • 在一台电脑中,可以运行成百上千个web服务,每个web服务都对应着一个唯一的端口号。客户端发送过来的网络请求,通过端口号,可以被准确的交给对应的web服务进行处理

注意:

  1. 每个端口号不能同时被多个web服务占用
  2. 在实际应用中,URL中的80端口可以省略

创建最基本的web服务器

创建web服务器的基本步骤

  1. 导入http模块
  2. 创建web服务器实例
    const server = http.createServer()
  3. 为服务器实例绑定request事件,监听客户端的请求
js 复制代码
//绑定request事件
server.on('request',(request,response)=>{
    console.log('someone visit our web server');
})
  1. 启动服务器
js 复制代码
//启动服务器
server.listen('8080',()=>{
    console.log('server running at http://127.0.0.1:8080');
})

request请求对象

  • request是请求对象,它包含了与客户端相关的数据和属性
  • request.url:是客户端请求的URL地址
  • request.method:是客户端的method的请求类型
    response响应对象
  • res.end()方法:向客户端发送指定的内容,并结束这次请求的处理过程
js 复制代码
const http = require('http')

const server = http.createServer()

server.on('request',(req,res)=>{
    const url = req.url;
    const method = req.method
    const str = `your request url = ${url},and your request method = ${method}`
    console.log(str);

    res.end(str)
})

server.listen('8080',()=>{
    console.log('http server running at http://127.0.0.1:8080');
})

解决中文乱码问题

  • 当调用res.end()方法向客户端发送中文内容的时候,会出现乱码问题,此时,需要手动设置内容的编码格式
js 复制代码
const http = require('http')
const server = http.createServer()

server.on('request',(req,res)=>{

    const str2 = '让我们红尘作伴'
    //设置Content-Type响应头,来解决中文乱码问题
    res.setHeader('Content-Type','text/html; charset=utf-8')
    console.log(str2);
    res.end(str2)
})

server.listen('8080',()=>{
    console.log('http server running at http://127.0.0.1:8080');
})

根据不同的URL响应不同的html内容

核心实现步骤:

  1. 获取请求的URL地址
  2. 设置默认的响应内容为 404 Not Found
  3. 判断用户的请求是否为/或者index.html首页
  4. 判断用户请求的是否为/about.html关于页面
  5. 设置Content-Type 响应头,防止中文乱码
  6. 使用res.end()将内容响应到客户端
js 复制代码
const http = require('http')
const server = http.createServer()

server.on('request',(req,res)=>{
    const url = req.url
    let content = '<h1>404 Not Found</h1>'
    if(url==='/' || url ==='/index.html'){
        content = '<h1>首页</h1>'
    }else if(url==='/about.html'){
        content = '<h1>关于页面</h1>'
    }
    res.setHeader('Content-Type','text/html; charset=utf-8')
    res.end(content)
})

server.listen('80',()=>{
    console.log('http server running at http://127.0.0.1');
})

模块化

Node.js中的模块化

加载模块

  • 使用强大的require()方法,可以加载需要的内置模块、用户自定义模块、第三方模块进行使用
    注意:使用require()方法加载模块时,会执行被加载模块中的代码

向外共享模块作用域的成员

module对象
  • 在每个.js自定义模块中都有一个module对象,它里面存储了和当前模块有关的信息。
js 复制代码
{
  id: '.',
  path: '/Users/miraculous/Desktop/前端/Node.js',
  exports: {},
  filename: '/Users/miraculous/Desktop/前端/Node.js/13-module对象.js',
  loaded: false,
  children: [],
  paths: [
    '/Users/miraculous/Desktop/前端/Node.js/node_modules',
    '/Users/miraculous/Desktop/前端/node_modules',
    '/Users/miraculous/Desktop/node_modules',
    '/Users/miraculous/node_modules',
    '/Users/node_modules',
    '/node_modules'
  ],
  [Symbol(kIsMainSymbol)]: true,
  [Symbol(kIsCachedByESMLoader)]: false,
  [Symbol(kIsExecuting)]: true
}
//以上为打印的module信息
module.exports对象
  • 在自定义模块中,可以使用module.exports对象,将模块内的成员共享出去,供外界使用
  • 外界用require()方法导入的自定义模块,得到的就是module.exports所指向的对象
js 复制代码
const username = 'zhengbo'
const add = (x,y)=>{
    return x + y
}
module.exports = {
    username,
    add
}
//以上为下面的导入模块

const obj = require('./14-module.exports向外共享对象')
console.log(obj);

注意:使用require()方法导入模块时,导入的结果,永远以module.exports指向的对象为准

exports对象

  • 为了简化向外共享成员的代码,Node提供了exports对象,默认情况下,exports和module.exports指向同一个对象。最终共享的结果。还是以module.exports指向的对象为准
    对比module.exports和exports
  • 直接对exports赋值不会改变module.exports的值,而module.exports的值才是通过require获取的内容
  • module.exports:用于直接导出模块的默认值,可以是任何类型
  • exports:用于导出模块的属性或方法,只能用于对象的属性赋值,不能直接赋值

注意:尽量不要在同一个模块中同时使用module.exports和exports,避免混淆

Node.js中的模块化规范

  • Node.js遵循了CommonJS的规范,CommonJS规定了模块的特性和各模块之间如何相互依赖
    CommonJS规定:
  1. 每个模块内部,module变量代表当前模块
  2. module变量是一个对象,它的exports属性(module.exports)是对外的接口
  3. 加载某个模块,其实是加载该模块的module.exports属性,require()方法用于加载模块

npm与包

  • Node.js中的第三方模块又叫做包

初次装包后多了哪些文件?

  • node_modules:用来存放所有已安装到项目的包。require()导入第三方包,就是从这个目录中查找并加载包
  • package-lock.json:用来记录node_modules目录下的每一个包的下载信息,例如:包的名字、版本号、下载地址等

注意:不要手动修改上面两个文件中的任何代码

包的语义化版本规范

  • 包的版本号是以"点分十进制"形式进行定义的,总共有三位数字,例如:2.24.0
  • 第一位数字:大版本
  • 第二位数字:功能版本
  • 第三位数字:BUG修复版本
  • 版本号提升规则:只要前面的版本号增长了,则后面的版本号归零

包管理配置文件

如何记录项目中安装了哪些包?

  • 在项目根目录中,创建一个叫做package.json的配置文件,即可用来记录项目中安装了哪些包。从而方便剔除node_modules目录之后,在团队成员之间共享项目的源代码

注意:一定要把node_moduled文件夹添加到.gitignore忽略文件中

快速创建package.json

  • 在执行命令所处的目录中,快速新建package.json文件
    npm init -y
    注意:上面的命令只能在英文的目录下成功运行,不能出现中文或者空格

一次性安装所有的包

  • 应用场景:当我们拿到了一个剔除了node_modules文件的项目之后,需要先把所有的包下载到项目中,这样项目才可以运行起来
  • 运行npm install或者npm i一次性安装所有的依赖包
  • 工作原理:执行上述命令时,npm包管理工具会先读取package.json中的dependencies节点,然后将它们一次性下载到项目中

卸载包

  • 使用npm uninstall命令,来卸载指定的包
    - npm uninstall + 指定包名
    注意:上述命令执行成功后,会把卸载的包从dependicies中自动移除
    Devdependencies
  • 如果某些包只在项目开发阶段会用到,在项目上线后并不会用到,建议将这些包devdependicies中
    npm install + 包名 -D

初始化自己的包

  1. 创建一个文件夹
  2. 并在该文件夹中创建package.json、index.js、README.md
js 复制代码
//package.json中的配置
{
    "name": "itheima-study-nodejs", //包的名字
    "version": "1.0.0", 
    "main": "index.js", //包的入口文件
    "description": "提供了格式化时间、HTMLEscape相关功能", //对包的描述
    "keywords": ["itheima","study"], //搜索包时的关键字
    "license":"ISC"
}

发布包

  1. 在npmjs官网注册账号
  2. 在终端登录账号
    注意:在运行npm login命令之前,必须先把下包的服务器地址切换为npm的官方服务器,否则会导致npm发包失败
  3. 将终端切换到包的根目录后,运行npm publish命令,即可将包发布到npm上(包名不能雷同)
    删除已发布的包
  • 运行npm unpublish 包名 --force命令,即可从npm删除已发布的包
  • 注意:
    • 该命令只能删除72小时之内发布的包
    • 该命令删除的包,在24小时之内不允许重复发布

模块的加载机制

优先从缓存中加载模块

  • 模块在第一次加载后会被缓存,这也意味着多次调用require()方法不会导致模块中的代码重复执行

内置模块的加载机制

  • 内置模块的加载优先级最高!
    自定义模块的加载机制
  • 在导入自定义模块时,如果省略了文件的扩展名,则Node.js会按下面的顺序分别尝试加载文件
  1. 按照确切的文件名进行加载
  2. 补全.js扩展名进行加载
  3. 补全.json扩展名进行加载
  4. 补全.node扩展名进行加载
  5. 加载失败,终端报错

第三方模块的加载机制

  • 现在node_modules中进行查找,如果没有则会往上一级目录去找,直到根目录为止
相关推荐
yinxiangzhongqing19 分钟前
深入理解JavaScript的执行机制
开发语言·前端·javascript
小画家~29 分钟前
第五十八:父传子 defineProps
前端·javascript·vue.js
青红光硫化黑32 分钟前
前端基础之组件
前端·javascript
codexu_46122918733 分钟前
Tauri跨端笔记实战(4) - 如何实现系统级截图
前端·笔记·rust·app·tauri
Q一件事41 分钟前
生态安全相关文献推荐
学习
汇能感知44 分钟前
不同类型光谱相机的技术差异比较
经验分享·笔记·科技
没资格抱怨1 小时前
Element Plus中的树组件的具体用法(持续更新!)
前端·javascript·算法
86Eric1 小时前
vue Table 表格自适应窗口高度,表头固定
javascript·vue.js·table 高度自适应·table 表头固定
朝九晚五ฺ1 小时前
【Linux探索学习】第三十二弹——生产消费模型:基于阻塞队列和基于环形队列的两种主要的实现方法
linux·运维·学习
老哥不老1 小时前
深入 Vue.js 组件开发:从基础到实践
vue.js·笔记