nodeJs的学习历程 -- 核心API (初学者基础篇)

257 阅读10分钟

nodeJs核心API

话不多说,直接进入主题 更多内容移步官网nodeJs

fs文件操作

以下文件的路径都是相对路径,会存在问题,后面会有优化

1、文件读取 -- fs.readFile

  • readFile有三个参数:
    • 参数1:path (被读取文件的路径)
    • 参数2:option(读取文件的内容以什么格式被编译,经常使用的是utf-8)
    • 参数3:callback (回调函数,读取文件之后的操作,接收两个参数)
      • 参数1:Error(读取文件失败的结果)
      • 参数2:data(读取文件成功的结果)
const fs = require('fs')
fs.readFile('./1.txt', 'utf-8', function (err, data) {
  if (err) return console.log('读取文件失败' + err.message)
  console.log('读取文件成功' + data)
})

2、 文件写入 -- fs.writeFile

重复写入不会报错,会覆盖上一次的文件内容

  • writeFile有四个参数:
    • 参数1:file (被读取文件的路径)
    • 参数2:写入文件的内容
    • 参数3:option(写入文件的内容以什么格式被编译,默认是utf-8)
    • 参数4:callback (回调函数,写入文件之后的操作,接收一个参数)
      • 参数:Error(读取文件失败的结果)
fs.writeFile('./2.txt','十月',function (err) { 
  console.log(err);   //null
 })

3、文件追加 -- fs.appendFile

追加的文件路径不存在,默认是先创建文件,然后再向文件中追加内容

  • appendFile有四个参数:
    • 参数1:file (被追加文件的路径)
    • 参数2:写入文件的内容
    • 参数3:option(写入文件的内容以什么格式被编译,默认是utf-8)
    • 参数4:callback (回调函数,写入文件之后的操作,接收一个参数)
      • 参数:Error(读取文件失败的结果)
fs.appendFile('./2.txt', '你好', function (err) {
  console.log(err)  //null
})

4、关于路径的优化__dirname

  • 使用相对路径,如果实在当前文件夹下执行,不会出现任何问题,如何不在当前文件下执行,会报错(找不到需要执行的文件)
[Error: ENOENT: no such file or directory, open 'D:\demo\file\2.txt'] {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'open',
  path: 'D:\\demo\\file\\2.txt'
}
  • 解决办法:使用__dirname拼接需要执行的文件的路径即可

    • __dirname:表示当前执行的文件所在的绝对路径

    -例子:

fs.appendFile(__dirname+'/file/2.txt', '你好', function (err) {
  console.log(err)
})

5、和__dirname相似的方法__filename

  • __filename理解:表示当前执行的文件的完整路径:路径中包含了具体的文件名

6、文件的状态fs.stat

  • fs.stat有三个参数:
    • 参数1:被判断文件的路径
    • 参数2:返回的 fs.Stats 对象中的数值是否为 bigint 型。 默认值: false。
    • 参数3:callback回调函数:其有两个参数
      • 参数1:Error 获取文件状态失败的数据
      • 参数2:stats:是一个对象,包含了文件的所有状态信息(大小、创建时间、判读是否是文件或者目录等等)

7、文件拷贝fs.copyFile

  • fs.copyFile有四个参数:
    • 参数1:要拷贝的源文件名

    • 参数2:拷贝操作的目标文件名。

    • 参数3:用于拷贝操作的修饰符。默认值: 0。

    • 参数4:callback回调函数,一个参数:Error,拷贝是否成功的返回值

path路径操作

1、path.join()路径拼接:里面的参数是一个个的拼接路径,应用场景:路径拼接,防止路径拼接错误导致工作效率降低, 示例代码 fs.appendFile(path.join(__dirname,'/file/2.txt'), '你好', function (err) { console.log(err) })

2、path.sep获取系统的分隔符号,windows是/,linux是\

3、path.basename获取路径的最后一部分

  • 两个参数:
    • 参数1:需要获取最后一部分的路径
    • 参数2:ext 可选的文件扩展名,当指定了最后一个参数,返回的值就会去除扩展名

4、path.dirname获取path的目录名,获取的结果是最后一个/之前的路径,只有一个参数:path路径

5、path,extname获取文件的扩展名,只接受一个参数path路径

单线程和异步简单介绍

1、重点记住三句话:

  • JavaScript的解析和执行一直是单线程的,但是宿主环境(浏览器或node)是多线程的

  • 异步任务是由宿主环境开启子线程完成,并通过事件驱动、回调函数、队列,把完成的任务,交给主线程执行

  • JavaScript解析引擎一直在做一个工作,就是从任务队列里提取任务,放到主线程里执行

模块化规范

1、nodeJs遵循的规范是commonJs,在浏览器端不支持commonJs,因为commonJs下,模块是异步加载的 2、每一个模块都有module、require、exports三个属性 3、模块向外暴露成员,在每一个模块中都是以module.exports为准(推荐) 4、AMD/CMD是commonJs在浏览器端的解决方案,在AMD/CMD下,模块都是异步加载的(现在也不行了) 5、主流的模块化是ES6的模块化,现在成为主流的浏览器和服务器通用的模块解决方案

包的介绍

1、什么是包:

  • 英文名叫做 Packages,包是在模块基础上更深一步的抽象;
  • 包的目的:方便分发和推广基于 CommonJS 规范实现的 应用程序 或 类库;
  • 包可以看作是 模块、代码 和 其它资源 组合起来形成的 独立作用域; 2、规范的包结构
  • 包都要以一个单独的目录而存在
  • package.json 必须在包的顶层目录下
  • package.json 文件必须符合 JSON 格式,并且必须包含如下三个属性:name, version, main
    • name: 包的名字
    • version: 包的版本号
    • main: 表示包的入口文件
  • 二进制文件应该在bin目录下;
  • javaScript代码应该在lib目录下;
  • 文档应该在doc目录下;
  • 单元测试应该在test目录下;
  • Node.js对包要求并没有那么严格,只要顶层目录下有package.json,并符合基本规范即可; 3、包描述文件 package.json
  • name:包的名称,必须是唯一
  • description:包的简要说明
  • version:符合语义化版本识别规范的版本字符串
  • keywords:关键字数据,通常用于搜索
  • maintainers:维护者数组,每个元素要包含name、email、web可选字段
  • contributors:贡献者数组,格式与maintainers相同。包的坐着应该是贡献者数据的第一个元素
  • bugs:提交bug的地址,可以是网址或者电子邮件地址
  • licenses:许可证数组,每个元素要包含type和url字段
  • repositories:仓库托管地址数组,每个元素要包含type、url和path字段
  • dependencies:包的依赖,一个关联数组,由包名称和版本号组成。
  • devDependencies:开发依赖项,表示一个包在开发期间用到的依赖项 4、包文件结构:以封装计算器为例

包文件结构.png

5、npm包的相关介绍

  • 全局安装和本地安装
    • 全局安装:安装到计算机全局环境中的包,叫做全局包;安装的全局包可以在当前电脑的任何目录下,直接通过命令行来访问;
      • 安装:npm install 包名 -g
      • 路径:C:\Users\用户目录\AppData\Roaming\npm
      • 卸载 npm uninstall 包名 -g
    • 本地安装:跟着项目安装的包,叫做本地包;本地包都会被安装到 node_modules 目录下;
      • 安装:npm i 包名 --save
      • 路径:项目根目录下node_moudles
      • 卸载:npm uninstall 包名 --save
  • npm常用命令:
    • --save 的缩写是 -S

    • --save-dev的缩写是 -D

    • install 的缩写是 i

    • 注意:dependencies 节点,表示项目上线部署时候需要的依赖项;devDependencies节点,表示项目在开发阶段需要的依赖项,但是当项目要部署上线了,devDependencies节点中的包,就不再需要了!

    • 注意:当使用 npm i快速装包的时候,npm会检查package.json文件中,所有的依赖项,然后都为我们安装到项目中

    • --production 表示只安装 dependencies 节点下,记录的包,不安装devDependencies节点下的包;当项目要上线了,才会使用--production命令

node构建服务器

6、node构建服务器

  • 创建服务器:使用 const server = http.createServer() 创建服务器;
  • 绑定监听事件:通过 server.on('request', function(req, res) { 请求的处理函数 }) 绑定事件 并 指定 处理函数;
  • 启动服务器:通过 server.listen(端口, IP地址, 启动成功的回调函数) 来启动服务器;
  • 防止响应内容中文乱码问题
    • 通过 设置响应报文头的 Content-Type,来指定响应内容的编码类型,从而防止乱码:
    res.writeHeader(200, { 
    'Content-Type': 'text/plain; charset=utf-8'}
    
  • 根据不同的URL返回不同的文本内容
    • 使用 req.url 获取客户端请求的URL地址
  • 根据不同的URL返回不同的HTML页面
    • 主要思路:使用 fs 模块 读取URL对应的HTML页面内容,并使用 res.end() 响应给客户端即可;
  • 最终实现的代码
const http = require('http')
const fs = require('fs')
const path = require('path')

const server = http.createServer()

server.on('request', function (req, res) {
  // req客户端相关的参数,res表示和服务器相关的参数和方法

  let url = req.url
  if (url==='/') url='/view/index.html'
  fs.readFile(path.join(__dirname,url),function (err,buffer) { 
    if(err) return res.end('404. Not Found.')
    res.end(buffer)
   })
})

server.listen(3000, '127.0.0.1', function () {
  console.log('服务器运行在 http://127.0.0.1:3000')
})

7、node结合art-template渲染动态页面

  • art-template官网:http://aui.github.io/art-template/zh-cn/
  • 示例项目:初始化项目npm init
  • 安装art-template依赖包:npm install art-template
  • 创建一个js文件,构建一个简单的服务器,同时引入art-template包
  • 创建一个html文件,
  • 完整代码如下:
    • js代码:

const http  = require("http");

const template  = require("art-template");
const path  = require("path");

// 创建服务器
const server=http.createServer()

server.on('request',function (req,res) { 
  const url=req.url
  if (url==='/') {
    const htmlStr=template(path.join(__dirname,'./index.html'),{name:'ls',age:'12',aihao:['睡觉','数钱','哈哈']})
    res.end(htmlStr)

  }
 })

 server.listen(8080,'127.0.0.1',function () { 
  console.log('服务器运行在: http://127.0.0.1:8080');
  })
  • html代码
 <!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div>动态渲染</div>
  <p>姓名 :{{name}}</p>
  <p>年龄 :{{age}}</p>
  <p>爱好 :
    {{each aihao}}
      <span>{{$value}}</span>
    {{/each}}
  </p>
</body>
</html>

8、nodemon工具的使用

  • 作用:能够实时监听当前项目中,文件的变化;只要监听到了文件的变化,则 nodemon 工具,会自动重新启动 web 服务器,从而使最新的代码生效;免去了程序员手动重启服务器的困扰;

  • 如何安装:运行 npm i nodemon -g 全局安装即可;

  • 如何使用

    • 之前使用 node 要执行的文件路径 来运行 Node.js 代码;
    • 现在使用 nodemon 要执行的文件路径 来运行 Node.js 代码;
  • 注意:今后在开发Web项目的时候,推荐使用 nodemon 来启动 web 服务器

express框架

9、Node 中开发web项目的框架 - express

  • express官网:https://www.expressjs.com.cn/
  • express 框架的特点:
    • 基于Node.js平台之上,进一步封装了 http 模块,从而提供了更好用,更友好的 API
    • 使用Express创建网站,比使用原生的http模块更加方便;
    • Express 并没有覆盖 原生 http 模块中的方法,而是基于 原生方法之上,做了更友好的封装,让用户体验更好
  • express 框架的安装和基本使用
    • 安装:运行 npm i express -S 即可安装
    • 创建基本的 express 服务器:
      • 导入 express 第三方模块;
      • 创建服务器的实例:调用 const app = express() 方法;
      • 通过 app.get() 或 app.post() 方法,来监听客户端的 get 或 post 请求,具体语法:
        • 监听 GET 请求:app.get('请求地址', (req, res) => { 处理函数 })
        • 监听 POST 请求: app.post('请求地址', (req, res) => { 处理函数 })
      • 启动 express 服务器:通过 app.listen(端口, IP地址, 启动成功后的回调函数) 启动服务器;
  • express 中的快捷方法
    • res.send()
      • 支持 发送 字符串 Content-Type: text/html;
      • 支持 发送 对象 或 数组 Content-Type: application/json
      • 支持 发送 Buffer 此时会当作文件下载
    • res.sendFile()
      • 用法1:res.sendFile(path.join(__dirname, './view/index.html'))
      • 用法2:res.sendFile('./view/movie.html', { root: __dirname })
      • 注意:res.sendFile() 可以向浏览器发送 静态页面;
  • express.static() 的静态资源托管
    • 语法1: app.use(express.static('public'));
      • app.use()方法,是专门用来注册 中间件;
      • express.static 是express的内置中间件;
const express  = require("express");

const app=express()

// 使用app.use进行中间件的注册

app.use(express.static('./view'))

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

  • 语法2:app.use('/虚拟目录', express.static('public'))
    • 在访问的路径前面加上公共的路径
const express  = require("express");

const app=express()

// 使用app.use进行中间件的注册

app.use('/page',express.static('./view'))

app.listen(8080,()=>{
  console.log('http://127.0.0.1:8080');
})
  • 为 express 框架配置模板引擎渲染动态页面(ejs后台引擎)
    • 安装 ejs 模板引擎npm i ejs -S

    • 使用 app.set() 配置默认的模板引擎 app.set('view engine', 'ejs')

    • 使用 app.set() 配置默认模板页面的存放路径 app.set('views', './views')

    • 使用 res.render() 来渲染模板页面res.render('index.ejs', { 要渲染的数据对象 }),注意,模板页面的 后缀名,可以省略不写!

    • js代码

const express  = require("express");


const app=express()

// 使用app.set()设置模板引擎
app.set('view engine', 'ejs')

app.set('views','./ejs_page')

app.get('/',(req,res)=>{
  res.render('index.ejs',{name:'zs',age:'20',hobby:['吃饭','睡觉']})
})

app.listen(8090,()=>{
  console.log('http://127.0.0.1:8090');
})
  • ejs模板引擎代码 :=是输出 <% %>是模板语法格式
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div>
    这是用ejs渲染的页面
  </div>
  <p>
    姓名:<%= name %>
  </p>
  <p>
    年龄:<%= age %>   
    <!-- =是输出  <%   %>是模板语法格式 -->
  </p>

  <% hobby.forEach(item=>{ %>
  <p> <%= item %></p> 

  <% }) %>
</body>
</html>
  • 在 express 中配置 art-template
    • 安装 两个包 cnpm i art-template express-art-template -S

    • 自定义一个模板引擎 app.engine('自定义模板引擎的名称', 渲染函数)

    • 将自定义的模板引擎,配置为 express 的默认模板引擎 app.set('view engine', '具体模板引擎的名称')

    • 配置 模板页面得存放路径 app.set('views', '路径')

    • js代码

const express = require('express');


const app=express()

// html是自定义的模板引擎的名称也是创建模板引擎的后缀名的名称
app.engine('html',require('express-art-template'))

app.set('view engine','html')

app.set('views','./art_page')


app.get('/',(req,res)=>{
  res.render('index.html',{name:'ls',age:12,hobby:['1','2','3']})
})
app.listen(8099,()=>{
  console.log('http://127.0.0.1:8099');
})
  • 模板引擎html代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div>
    这是使用art-template渲染的页面
  </div>

  <div>姓名:{{name}}</div>
  <div>年龄{{age}}</div>
{{each hobby}}
  <div>
    {{$index}}
    {{$value}}
  </div>

{{/each}}
</body>
</html>
  • 使用 express 框架中提供的路由来分发请求(路由的介绍)
    • 什么是路由:路由就是对应关系;
    • 什么叫做后端路由:前端请求的URL地址,都要对应一个后端的处理函数,那么 这种URL地址到 处理函数之间的对应关系,就叫做后端路由;
    • 在Express中,路由的主要职责 就是 把请求分发到对应的处理函数中;
    • 在Express中,如何 定义并使用路由呢?
// 1. 封装单独的 router.js 路由模块文件
  const express = require('express')
  // 创建路由对象
  const router = express.Router()

  router.get('/', (req, res)=>{})
  router.get('/movie', (req, res)=>{})
  router.get('/about', (req, res)=>{})

  // 导出路由对象
  module.exports = router 
  • express 创建的 app 服务器,如何使用 路由模块呢?
// 导入自己的路由模块
const router = require('./router.js')
// 使用 app.use() 来注册路由
app.use(router)

10、Express 框架里 中间件的概念

  • 什么是中间件
    • 定义:中间件就是一个处理函数;只不过这个函数比较特殊,包含了三个参数,分别是 req,res,next

注意:中间件方法中的三个参数:

  • req:请求对象;

  • res:响应对象;

  • next:next()可以被调用,表示调用下一个中间件方法;

  • Express 框架中对中间件的5种分类 (了解)

    • 应用级别的中间件: 挂载到 app 上的中间件 app.get('URL地址', (req, res, next)=> {});
    • 路由级别的中间件: 挂载到 router 对象上的中间件 router.get('url地址', (req, res, next)=>{})
    • 错误级别的中间件: 回调函数中,有四个参数 app.use((err, req, res, next)=>{})
    • 唯一内置的中间件: express.static()
    • 第三方中间件: 非express框架提供的,需要程序员手动安装才能使用的中间件;body-parser 解析post 表单数据
  • 自定义解析表单数据的中间件

const express  = require("express");
const querystring  = require("querystring");

const app=express()

app.use((req,res,next)=>{
  let dataStr=''
  // 只要客户端向服务器提交了表单,都会触发req的data事件
  // 在data事件中可以获取到客户端每次提交过来的不完整的数据
  req.on('data',chunk=>{
    dataStr+=chunk
  })


  // 只要req触发了end事件,就表示表单数据提交完毕了,dataStr中存储的数据就是完整的表单数据
  req.on('end',()=>{
    console.log('结束',dataStr);
    // 将获得表单数据格式化,querystring.parse()
    let str=querystring.parse(dataStr)

    req.body=str
    // 注意!在中间件中,最后一定要合理的调用一下next()方法,否则服务器无法结束这次响应
    next()
  })
})

app.get('/',(req,res)=>{
  res.sendFile('./index.html',{root:__dirname})
})

app.post('/formSub',(req,res)=>{
  // 拿到从客户端提交的数据
  
  res.send(req.body)
})
app.listen(9090,function () { 
  console.log('sercer running at http://127.0.0.1:9090');
 })

基础的我暂时学到这里,后面会继续更新的