程序笔记   发布时间:2022-07-12  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了Node.js b站教学视频汇总笔记(完)CommonJS模块规范、 require、npm、Express(中间件)、MongoDB、MySQL大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
@H_450_5@

文章目录

  • Node.js b站教学视频汇总笔记(完)CommonJS模块规范、 require、npm、Express(中间件)、MongoDB、MySQL
  • 1. Node介绍
    • 为什么要学习Node.js
    • Node.js是什么
    • Node能做什么
  • 2. 起步
    • 安装Node环境
    • 解析执行JavaScript
    • 文件的读写
    • http
      • 端口号(范围0~65536之间)
  • 3. Node中的模块系统
    • 什么是模块化
    • CommonJS模块规范
      • 加载`require`
      • 导出`exports`
    • 模块原理
    • 总结
  • 4. require的加载规则
    • require的加载规则:
    • 模块标识符中的`/`和文件操作路径中的`/`
  • 5. npm
      • npm网站
      • npm命令行工具
      • 常用命令
      • 解决npm被墙问题
  • 6. package.json
    • package.json和package-lock.json
    • path路径操作模块
  • 7. Node中的其它成员(__dirname,__fileName)
  • 8. Express(快速的)
      • 学习Express
        • 起步
          • 安装:
          • Hello world:
          • 基本路由
          • Express静态服务API
          • 在Express中配置使用`art-templete`模板引擎
          • 在Express中获取表单请求数据
            • 获取get请求数据:
            • 获取post请求数据:
      • 在Express中配置使用`express-session`插件操作
      • 利用Express实现ADUS项目
        • 模块化思想
        • 起步
        • 路由设计
        • 提取路由模块
        • 设计操作数据的API文件模块
        • 步骤
        • 子模板和模板的继承(模板引擎高级语法)【include࿰c;extend࿰c;block】
  • 9. MongoDB
    • 关系型和非关系型数据库
      • 关系型数据库(表就是关系࿰c;或者说表与表之间存在关系)。
      • 非关系型数据库
    • 安装
    • 启动和关闭数据库
    • 连接数据库
    • 基本命令
    • 在Node中如何操作MongoDB数据库
      • 使用官方的`MongoDB`包来操作
      • 使用第三方包`mongoose`来操作MongoDB数据库
    • 学习指南(步骤)
      • 设计scheR_515_11845@e 发布Model (创建表)
      • 添加数据(增)
      • 删除(删)
      • 更新(改)
      • 查询(查)
  • 10. 使用Node操作MySQL数据库
  • 异步编程
    • 回调函数
    • Promise
    • Generator
  • 11. 其他
    • 修改完代码自动重启
    • 封装异步API
    • 数组的遍历方法࿰c;都是对函数作为一种参数
    • EcmaScript 6
  • 12. 项目案例
    • 目录结构
    • 模板页
    • 路由设计
    • 模型设计
    • 功能实现
    • 步骤
  • 13. Express中间件
    • 中间件的概念
    • 中间件的分类:
      • 应用程序级别的中间件
      • 路由级别的中间件
    • 错误处理中间件
    • 内置中间件
    • 第三方中间件
@H_450_5@

Node.js b站教学视频汇总笔记(完)CommonJS模块规范、 require、npm、Express(中间件)、MongoDB、MySQL

@H_450_5@总结:

  • @H_450_5@通用

    • @H_450_5@Node.js安装包:http://nodejs.cn/download/。

    • @H_450_5@API检索网址:API 文档 | Node.js 中文网 (nodejs.cn)

    • @H_450_5@第三方模板引擎:art-template官方文档

    • @H_450_5@npm init 生成 package.json文件

    • @H_450_5@Express:

      • 提供了创建 Web 服务器的最简单但功能最强大的方法之一。 它的极简主义方法࿰c;专注于服务器的核心功能࿰c;是其成功的关键。
      • 基于 Node.js 平台࿰c;快速、开放、极简的 Web 开发框架。
    • @H_450_5@koa: 由 Express 背后的同一个团队构建࿰c;旨在变得更简单更轻巧。 新项目的诞生是为了满足创建不兼容的更改而又不破坏现有社区。

    • @H_450_5@readyState

      • 存有 XMLhttprequest 的状态。从 0 到 4 发生变化。
      • 0: 请求未初始化
      • 1: 服务器连接已建立
      • 2: 请求已接收
      • 3: 请求处理中
      • 4: 请求已完成࿰c;且响应已就绪
    • @H_450_5@status

      • 200, OK࿰c;访问正常
      • 301, Moved Pe@R_673_11065@ently࿰c;永久移动
      • 302, Moved temporarily࿰c;暂时移动
      • 304, Not Modified࿰c;未修改
      • 307, Temporary Redirect࿰c;暂时重定向
      • 401, Unauthorized࿰c;未授权
      • 403, Forbidden࿰c;禁止访问
      • 404, Not Found࿰c;未发现指定网址
      • 500, Internal Server Error࿰c;服务器发生错误
    • @H_450_5@mIME Type

      • @H_450_5@mIME (MultipurposE internet Mail Extensions) 是描述消息内容类型的因特网标准࿰c;说白了也就是文件的媒体类型。浏览器可以根据它来区分文件࿰c;然后决定什么内容用什么形式来显示。

      • @H_450_5@首先࿰c;我们要了解浏览器是如何处理内容的。在浏览器中显示的内容有 HTML、有 XML、有 GIF、还有 Flash ……那么࿰c;浏览器是如何区分它们࿰c;决定什么内容用什么形式来显示呢?答案是 MIME Type࿰c;也就是该资源的媒体类型。

      • @H_450_5@媒体类型通常是通过 http 协议࿰c;由 Web 服务器告知浏览器的࿰c;准确地说c;是通过 Content-Type 来表示的࿰c;例如:

        @H_450_5@Content-Type: text/HTML

        • 表示内容是 text/HTML 类型࿰c;也就是超文本文件。为什么是“text/HTML”而不是“HTML/text”或者别的什么?MIME Type 不是个人指定的࿰c;是经过 ietf 组织协商࿰c;以 RFC 的形式作为建议的标准发布在网上的࿰c;大多数的 Web 服务器和用户代理都会支持这个规范 (顺便说一句࿰c;Email 附件的类型也是通过 MIME Type 指定的)。
  • @H_450_5@简介

    • @H_450_5@定义

      • 通俗易懂的讲࿰c;Node.js是JavaScript的运行平台c;Node.js既不是语言࿰c;也不是框架࿰c;它是一个平台
      • Node.js 应用程序运行于单个进程中࿰c;无需为每个请求创建新的线程。 Node.js 在其标准库中提供了一组异步的 I/O 原生功能(用以防止 JavaScript 代码被阻塞)࿰c;并且 Node.js 中的库通常是使用非阻塞的范式编写的(从而使阻塞行为成为例外而不是规范)。
    • @H_450_5@CommonJS 模块系统

      • @H_450_5@Node.js 使用 CommonJS 模块系统࿰c;而在浏览器中࿰c;则还正在实现 ES 模块标准

        @H_450_5@在实践中࿰c;这意味着在 Node.js 中使用 require()c;而在浏览器中则使用 import

    • @H_450_5@Webpack五大核心

      • @H_450_5@entry:webpack打包的入口࿰c;其取值可以是字符串࿰c;数组或者一个对象

      • @H_450_5@output:webpack打包的输出

      • @H_450_5@@H_546_321@mode:webpack打包分为两种模式࿰c;开发模式(development)与生产模式(production)࿰c;默认为生产模式

        @H_450_462@@H_450_462@@H_450_462@
        选项描述
        development会将 process.env.NODE_ENV 的值设为 development。启用 NamedChunksPlugin 和 NamedModulesPlugin。
        production会将 process.env.NODE_ENV 的值设为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, occurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin.
      • @H_450_5@loader:webpack默认只能处理js、json格式的文件࿰c;而loader的作用则是将其他格式的文件࿰c;转换成webpack能够处理的文件

      • @H_450_5@plugin:webpack插件࿰c;每一个插件都有一个特定的功能࿰c;它能处理loader无法处理的事情。插件的使用非常简单࿰c;在PLugins数组中添加插件的实例化对象即可

  • @H_450_5@CLI

    • @H_450_5@命令行界面(英语:command-linE interfacec;缩写:CLI)是在图形用户界面得到普及之前使用最为广泛的用户界面࿰c;它通常不支持鼠标࿰c;用户通过键盘输入指令࿰c;计算机接收到指令后࿰c;予以执行。也有人称之为字符用户界面(CUI)。

    • @H_450_5@通常认为࿰c;命令行界面(CLI)没有图形用户界面(GUI)那么方便用户操作。因为࿰c;命令行界面的软件通常需要用户记忆操作的命令࿰c;但是࿰c;由于其本身的特点࿰c;命令行界面要较图形用户界面节约计算机系统的资源。在熟记命令的前提下࿰c;使用命令行界面往往要较使用图形用户界面的操作速度要快。所以࿰c;图形用户界面的操作系统中࿰c;都保留着可选的命令行界面。

    • @H_450_5@Node使用:

      • EcmaScript语言
        • 和浏览器一样࿰c;在Node中没有Bom和Dom
      • 核心模块
        • process
          • process.exit()
          • process.env.NODE_ENV
        • 文件操作的fs
        • http服务操作的http
        • url路径操作模块
        • path路径处理模块
        • os操作系统信息
      • 第三方模块
        • art-template: art-template官方文档
        • 必须通过npm来下载才可以使用。node package manage(node包管理器)
      • 自己写的模块
        • 自己创建的文件
  • @H_450_5@CommonJS 模块规范

    • 在Node中的JavaScript还有一个重要的概念࿰c;模块系统。
      • 模块作用域
      • 使用require方法来加载模块
      • 使用exports接口对象来导出模板中的成员
  • @H_450_5@package.json

    • @H_450_5@每一个项目都要有一个package.json文件(包描述文件࿰c;就像产品的说明书一样)

    • @H_450_5@这个文件可以通过npm init自动初始化出来

  • @H_450_5@Express

    • 原生的http在某些方面表现不足以应对我们的开发需求࿰c;所以就需要使用框架来加快我们的开发效率࿰c;框架的目的就是提高效率࿰c;让我们的代码高度统一。
  • @H_450_5@Node.js REPL

    • @H_450_5@REPL 也被称为运行评估打印循环࿰c;是一种编程语言环境(主要是控制台窗口)࿰c;它使用单个表达式作为用户输入࿰c;并在执行后将结果返回到控制台

      @H_450_5@如果在终端中尝试࿰c;会出现如下:

      ❯ node
      >
      
      @H_450_5@该命令会保持空闲状态࿰c;并等待输入内容。

      @H_450_5@确切地说࿰c;REPL 正在等待输入一些 JavaScript 代码。

      @H_450_5@从简单开始࿰c;输入:

      > console.log('测试')
      测试
      undefined
      >
      
      @H_450_5@第一个值 测试 是告诉控制台要打印的输出࿰c;然后得到 undefinedc;它是运行 console.log() 的返回值。

      @H_450_5@现在可以输入一行新的 JavaScript。

  • @H_450_5@console

    • %s 会格式化变量为字符串
    • %d 会格式化变量为数字
    • %i 会格式化变量为其整数部分
    • %o 会格式化变量为对象
  • @H_450_5@lodash

    • 中文网:Lodash 简介 | Lodash 中文文档 | Lodash 中文网 (lodashjs.com)
    • Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库。
    • lodash是对各种方法、函数的封装࿰c;使得使用更加方便c;具体的使用方法可以参见lodash官网中的介绍。
  • @H_450_5@npx

    • npx是一个工具࿰c;npm v5.2.0引入的一条命令(npx)࿰c;一个npm包执行器࿰c;指在提高从npm注册表使用软件包时的体验 ࿰c;npm使得它非常容易地安装和管理托管在注册表上的依赖项࿰c;npx使得使用CLI工具和其他托管在注册表。它大大简化了一些事情。
    • 就像npm极大地提升了我们安装和管理包依赖的体验࿰c;在Npm的基础之上࿰c;npx让npm包中的命令行工具和其他可执行文件在使用上变得更加简单。它极大地简化了我们之前使用纯粹的npm时所需要的大量步骤。
    • 主要特点
      • 临时安装可执行依赖包࿰c;不用全局安装࿰c;不用担心长期的污染
      • 可以执行依赖包中的命令࿰c;安装完成自动运行。
      • 自动加载node_modules中依赖包࿰c;不用指定$PATH。
      • 可以指定node版本、命令的版本࿰c;解决了不同项目使用不@R_9_11197@的命令的问题。
  • @H_450_5@npm

    • @H_450_5@Yarn 是 npm 的一个替代选择。

    • @H_450_5@默认软件包会被安装到当前文件树中的 node_modules 子文件夹下

    • @H_450_5@使用 -g 标志可以执行全局安装

    • @H_450_5@把可执行文件放到 node_modules/.bin/ 文件夹下

    • @H_450_5@升级

      • @H_450_5@若要将所有软件包更新到新的主版本c;则全局地安装 npm-check-updates 软件包:

        npm install -g npm-check-updates
        
        @H_450_5@然后运行:

        ncu -u
        
        @H_450_5@这会升级 package.json 文件的 dependenciesdevDependencies 中的所有版本࿰c;便 npm 可以安装新的主版本。

  • @H_450_5@package.json

    • @H_450_5@@H_723_435@main 设置了应用程序的入口点。

    • @H_450_5@scripts 定义了一组可以运行的 node 脚本

    • @H_450_5@private 如果设置为 truec;则可以防止应用程序/软件包被意外地发布到 npm

    • @H_450_5@dependencies 设置了作为依赖安装的 npm 软件包的列表。

    • @H_450_5@devDependencies 设置了作为开发依赖安装的 npm 软件包的列表。

      @H_450_5@它们不同于 dependenciesc;因为它们只需安装在开发机器上࿰c;而无需在生产环境中运行代码

    • @H_450_5@@R_674_10846@nes 设置了此软件包/应用程序在哪个版本的 Node.js 上运行。

    • @H_450_5@browserslist 用于告知要支持哪些浏览器(及其版本)

  • @H_450_5@package-lock.json

    • 会固化当前安装的每个软件包的版本c;当运行 npm install时࿰c;npm 会使用这些确切的版本。
    • 如果写入的是 〜0.13.0c;则只更新补丁版本:即 0.13.1 可以࿰c;0.14.0 不可以。
    • 如果写入的是 ^0.13.0c;则要更新补丁版本和次版本:即 0.13.10.14.0、依此类推。
    • 如果写入的是 0.13.0c;则始终使用确切的版本。
  • @H_450_5@语义版本

    @H_450_5@语义版本控制的概念很简单:所有的版本都有 3 个数字:x.y.z

    • 第一个数字是主版本。
    • 第二个数字是次版本。
    • 第三个数字是补丁版本。
      • ^: 只会执行不更改最左边非零数字的更新。 如果写入的是 ^0.13.0c;则当运行 npm update 时࿰c;可以更新到 0.13.10.13.2 等࿰c;但不能更新到 0.14.0 或更高版本。 如果写入的是 ^1.13.0c;则当运行 npm update 时࿰c;可以更新到 1.13.11.14.0 等࿰c;但不能更新到 2.0.0 或更高版本。
      • ~: 如果写入的是 〜0.13.0c;则当运行 npm update 时࿰c;会更新到补丁版本:即 0.13.1 可以࿰c;0.14.0 不可以。
      • >: 接受高于指定版本的任何版本。
      • >=: 接受等于或高于指定版本的任何版本。
      • <=: 接受等于或低于指定版本的任何版本。
      • <: 接受低于指定版本的任何版本。
      • =: 接受确切的版本。
      • -: 接受一定范围的版本。例如:2.1.0 - 2.6.2
      • ||: 组合集合。例如 < 2.1 || > 2.6
  • @H_450_5@卸载npm包

    • 移除 package.json 文件中的引用:使用 -S--save 标志
    • 如果程序包是开发依赖项(列出在 package.json 文件的 devDependencies 中)࿰c;则必须使用 -D--save-dev 标志从文件中移除
    • 如果该软件包是全局安装的࿰c;则需要添加 -g--global 标志
  • @H_450_5@http

    • GET、POST
      • GET请求的数据会附在URL之后(就是把数据放置在http协议头中)࿰c;以?分割URL和传输数据࿰c;参数之间以&相连࿰c;如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0%E5%A5%BD。如果数据是英文字母或数字࿰c;则原样发送;如果是空格࿰c;转换为+;如果是中文或其他字符࿰c;则直接把字符串用BASE64加密࿰c;得出如:%E4%BD%A0%E5%A5%BD࿰c;其中࿰5;XX中的XX为该符号以16进制表示的ASCII码值。而与之对应的࿰c;POST把提交的数据放置在http包的包体中࿰c;文章最下面将会有代码示例。
      • POST的安全性要比GET的安全性高。注意:这里所说的安全性和上面GET提到的“安全”不是同个概念。上面“安全”的含义仅仅是不作数据修改࿰c;而这里安全的含义是真正的Security的含义。比如:通过GET提交数据࿰c;用户名和密码将明文出现在URL上࿰c;因为:(1)登录页面有可能被浏览器缓存࿰c;(2)其他人查看浏览器的历史纪录࿰c;那么别人就可以拿到你的账号和密码了࿰c;除此之外࿰c;使用GET提交数据还可能会造成Cross-site request forgery攻击(CSRF,跨站请求伪造࿰c;也被称为:one click attack/session riding)。
  • @H_450_5@fs文件模块

    • @H_450_5@fs.open()

      • fs.open('/Users/joe/test.txt', 'R', (err, fd) => {
          //fd 是文件描述符。
        })
        
      • @H_450_5@r+ 打开文件用于读写。

      • @H_450_5@w+ 打开文件用于读写࿰c;将流定位到文件的开头。如果文件不存在则创建文件。

      • @H_450_5@a 打开文件用于写入࿰c;将流定位到文件的末尾。如果文件不存在则创建文件。

      • @H_450_5@a+ 打开文件用于读写࿰c;将流定位到文件的末尾。如果文件不存在则创建文件。

    • @H_450_5@fs.stat()

      • 每个文件都带有一组详细信息࿰c;可以使用 fs.stat() 进行检查。
      • 使用 stats.isFile()stats.isDirectory() 判断文件是否目录或文件。
      • 使用 stats.isSymbolicLink() 判断文件是否符号链接。
      • 使用 stats.size 获取文件的大小(以字节为单位)。
    • @H_450_5@路径

      • dirname: 获取文件的父文件夹。
      • basename: 获取文件名部分。
      • extname: 获取文件的扩展名。
      • 如果第一个参数以斜杠开头࿰c;则表示它是绝对路径
      • path.join() 连接路径的两个或多个片段
      • path.resolve() 获得相对路径的绝对路径计算
      • path.normalize() 当包含诸如 ... 或双斜杠之类的相对说明符时࿰c;其会尝试计算实际的路径
    • @H_450_5@读取文件

      • @H_450_5@fs.readFile() 方法: Node.js 中读取文件最简单的方式

      • @H_450_5@fs.readFileSync():同步的版本

      • @H_450_5@fs.readFile()fs.readFileSync() 都会在返回数据之前将文件的全部内容读取到内存中。

        @H_450_5@这意味着大文件会对内存的消耗和程序执行的速度产生重大的影响。

        @H_450_5@在这种情况下࿰c;更好的选择是使用流来读取文件的内容。

    • @H_450_5@写入文件

      • fs.writeFile() API
      • fs.writeFileSync()
      • fs.appendFile()(及其对应的 fs.appendFileSync())追加到文件末尾
    • @H_450_5@文件夹

      • fs.access() 检查文件夹是否存在以及 Node.js 是否具有访问权限
      • fs.mkdir()fs.mkdirSync() 可以创建新的文件夹
      • fs.readdir()fs.readdirSync() 可以读取目录的内容
      • fs.rename()fs.renameSync() 可以重命名文件夹
      • fs.rmdir()fs.rmdirSync() 可以删除文件夹
      • 删除包含内容的文件夹可能会更复杂。最好安装 fs-extra 模块
  • @H_450_5@buffer

  • @H_450_5@Buffer 是内存区域。可以将 buffer 视为整数数组࿰c;每个整数代表一个数据字节。

  • @H_450_5@Buffer 被引入用以帮助开发者处理二进制数据࿰c;在此生态系统中传统上只处理字符串而不是二进制数据。

    @H_450_5@Buffer 与流紧密相连。 当流处理器接收数据的速度快于其消化的速度时࿰c;则会将数据放入 buffer 中。

    @H_450_5@一个简单的场景是:当观看 YouTube 视频时࿰c;红线超过了观看点:即下载数据的速度比查看数据的速度快࿰c;且浏览器会对数据进行缓冲。

  • @H_450_5@流

    • @H_450_5@流是为 Node.js 应用程序提供动力的基本概念之一。它们是一种以高效的方式处理读/写文件、网络通信、或任何类型的端到端的信息交换。

    • @H_450_5@Node.js 的 stream 模块 提供了构建所有流 API 的基础。 所有的流都是 EventEmitter 的实例。

    • @H_450_5@优点

      • 内存效率: 无需加载大量的数据到内存中即可进行处理。
      • 时间效率: 当获得数据之后即可立即开始处理数据࿰c;这样所需的时间更少࿰c;而不必等到整个数据有效负载可用才开始。
    • @H_450_5@stream.pipe(res)

      • @H_450_5@它获取来源流࿰c;并将其通过管道传输到目标流。

      • @H_450_5@pipe() 方法的返回值是目标流࿰c;这是非常方便的事情࿰c;它使得可以链接多个 pipe() 调用࿰c;如下所示:

        src.pipe(dest1).pipe(dest2)
        
    • @H_450_5@分类

      • Readable: 可以通过管道读取、但不能通过管道写入的流(可以接收数据࿰c;但不能向其发送数据)。 当推送数据到可读流中时࿰c;会对其进行缓冲࿰c;直到使用者开始读取数据为止。
      • Writable: 可以通过管道写入、但不能通过管道读取的流(可以发送数据࿰c;但不能从中接收数据)。
      • Duplex: 可以通过管道写入和读取的流࿰c;基本上相对于是可读流和可写流的组合。
      • Transform: 类似于双工流、但其输出是其输入的转换的转换流。
  • @H_450_5@TypeScript

    • 它是 JavaScript 的超集࿰c;为语言增加了新的功能。
    • 最值得注意的新功能是静态类型定义c;这是普通 JavaScript 中所没有的。
    • 多亏于类型࿰c;我们可以声明期望的参数类型࿰c;以及在函数中确切返回的参数࿰c;或者所创建对象的确切是什么。
    • TypeScript 是一个非常强大的工具࿰c;它在 JavaScript 项目中开辟了可能性的新世界。
    • 通过在代码交付之前防止大量错误࿰c;它使我们的代码更安全࿰c;更健壮 - 它会在编写代码时@R_675_10005@࿰c;并与 Visual studio Code 这样的代码编辑器完美集成。

1. Node介绍

为什么要学习Node.js

  • 企业需求
    • 具有服务端开发经验更改
    • front-end
    • BACk-end
    • 全栈开发工程师
    • 基本的网站开发能力
      • 服务端
      • 前端
      • 运维部署
    • 多人社区

Node.js是什么

  • Node.js是JavaScript 运行时
  • 通俗易懂的讲࿰c;Node.js是JavaScript的运行平台
  • Node.js既不是语言࿰c;也不是框架࿰c;它是一个平台
  • 浏览器中的JavaScript
    • EcmaScript
      • 基本语法
      • if
      • var
      • function
      • Object
      • Array
    • Bom
    • Dom
  • Node.js中的JavaScript
    • 没有Bom࿰c;Dom
    • EcmaScript
    • 在Node中这个JavaScript执行环境为JavaScript提供了一些服务器级别的API
      • 例如文件的读写
      • 网络服务的构建
      • 网络通信
      • http服务器
  • 构建与Chrome的V8引擎之上
    • 代码只是具有特定格式的字符串
    • 引擎可以认识它࿰c;帮你解析和执行
    • Google Chrome的V8引擎是目前公认的解析执行JavaScript代码最快的
    • Node.js的作者把Google Chrome中的V8引擎移植出来࿰c;开发了一个独立的JavaScript运行时环境
  • Node.js uses an envent-driven,non-blocking I/O mode that makes it lightweight and efficent.
    • envent-driven 事件驱动
    • non-blocking I/O mode 非阻塞I/O模型(异步)
    • ightweight and efficent. 轻量和高效
  • Node.js package ecosystem,npm,is the larget scosystem of open sourcr libraries in the world
    • npm 是世界上最大的开源生态系统
    • 绝大多数JavaScript相关的包都存放在Npm上࿰c;这样做的目的是为了让开发人员更方便的去下载使用
    • npm install jquery

Node能做什么

  • web服务器后台
  • 命令行工具
    • npm(nodE)
    • git(c语言)
    • hexo(node)
  • 对于前端工程师来讲࿰c;接触最多的是它的命令行工具
    • 自己写的很少࿰c;主要是用别人第三方的
    • webpack
    • gulp
    • npm

2. 起步

安装Node环境

  • 查看Node环境的版本号
  • 下载:https://nodejs.org/en/
  • 安装:
    • 傻瓜式安装࿰c;一路next
    • 安装过@R_440_10696@会升级
  • 确认Node环境是否安装成功
    • 查看node的版本号:node --version
    • 或者node -v
  • 配置环境变量

解析执行JavaScript

  1. 创建编写JavaScript脚本文件
  2. 打开终端࿰c;定位脚本文件的所属目录
  3. 输入node 文件名执行对应的文件
  4. @H_373_1555@ @H_450_5@注意:文件名不要用node.js来命名࿰c;也就是说除了node这个名字随便起࿰c;最好不要使用中文。

    文件的读写

    @H_450_5@文件读取:

    //浏览器中的JavaScript是没有文件操作能力的
    //但是Node中的JavaScript具有文件操作能力
    //fs是file-system的简写࿰c;就是文件系统的意思
    //在Node中如果想要进行文件的操作就必须引用fs这个核心模块
    //在fs这个和兴模块中࿰c;就提供了人所有文件操作相关的API
    //例如 fs.readFile就是用来读取文件的
    
    //  1.使用fs核心模块
    var fs = require('fs');
    
    // 2.读取文件
    fs.readFile('./data/a.txt',function(err,data){
       if(err){
            console.log('文件读取失败');
       }
        else{
             console.log(data.toString());
        }
    })
    
    @H_450_5@文件写入:

    //  1.使用fs核心模块
    var fs = require('fs');
    
    // 2.将数据写入文件
    fs.writeFile('./data/a.txt','我是文件写入的信息',function(err,data){
       if(err){
            console.log('文件写入失败');
       }
        else{
             console.log(data.toString());
        }
    })
    

    http

    @H_450_5@服务器:

    // 1.加载http核心模块
    var http = require('http');
    
    // 2.使用http.createServer()创建一个web服务器
    var server = http.createServer();
    
    // 3.服务器要做的事儿
    // 提供服务:对数据服务
    // 发请求
    //	接收请求
    //	处理请求
    //	反馈(发送响应)
    //	当客户端请求过来࿰c;就会自动触发服务器的request请求事件࿰c;然后执行第二个参数:回调处理函数
    server.on('Request',function(){
        console.log('收到客户的请求了')
    })
    
    // 4.绑定端口号࿰c;启动服务
    server.listen(3000,function(){
        console.log('Runing...')
    })
    
    

    端口号(范围0~65536之间)

    @H_450_5@

    Node.js b站教学视频汇总笔记(完)CommonJS模块规范、 require、npm、Express(中间件)、MongoDB、MySQL

    Node.js b站教学视频汇总笔记(完)CommonJS模块规范、 require、npm、Express(中间件)、MongoDB、MySQL

    Node.js b站教学视频汇总笔记(完)CommonJS模块规范、 require、npm、Express(中间件)、MongoDB、MySQL

    注意:可以同时开启多个服务࿰c;但一定要确保不同的服务占用的端口号不一致࿰c;说的通俗易懂点儿࿰c;在一台计算机上一次一个端口号只能开启一个服务。

    3. Node中的模块系统

    @H_450_5@使用Node编写应用程序主要就是在使用:

    • @H_450_5@EcmaScript语言

      • 和浏览器一样࿰c;在Node中没有Bom和Dom
    • @H_450_5@核心模块

      • 文件操作的fs
      • http服务操作的http
      • url路径操作模块
      • path路径处理模块
      • os操作系统信息
    • @H_450_5@第三方模块

      • art-template
      • 必须通过npm来下载才可以使用
    • @H_450_5@自己写的模块

      • 自己创建的文件

    什么是模块化

    • 文件作用域(模块是独立的࿰c;在不同的文件使用必须要重新引用)【在Node中没有全局作用域࿰c;它是文件模块作用域】
    • 通信规则
      • 加载require
      • 导出exports

    CommonJS模块规范

    @H_450_5@在Node中的JavaScript还有一个重要的概念࿰c;模块系统。

    • @H_450_5@模块作用域

    • @H_450_5@使用require方法来加载模块

    • @H_450_5@使用exports接口对象来导出模板中的成员

      加载require

      @H_450_5@语法:

      var 自定义变量名 = require('模块')
      
      @H_450_5@作用:

      • 执行被加载模块中的代码
      • 得到被加载模块中的exports导出接口对象

      导出exports

      • @H_450_5@Node中是模块作用域࿰c;默认文件中所有的成员只在当前模块有效

      • @H_450_5@对于希望可以被其他模块访问到的成员࿰c;我们需要把这些公开的成员都挂载到exports接口对象中就可以了

        @H_450_5@导出多个成员(必须在对象中):

        exports.a = 123;
        exports.b = function(){
            console.log('bbb')
        };
        exports.c = {
            foo:"bar"
        };
        exports.d = 'hello';
        
        @H_450_5@导出单个成员(拿到的就是函数࿰c;字符串):

        @H_723_435@module.exports = 'hello';
        
        @H_450_5@以下情况会覆盖:

        @H_723_435@module.exports = 'hello';
        //后者会覆盖前者
        module.exports = function add(x,y) {
            return x+y;
        }
        
        @H_450_5@也可以通过以下方法来导出多个成员:

        @H_723_435@module.exports = {
            foo = 'hello',
            add:function(){
                return x+y;
            }
        };
        

    模块原理

    @H_450_5@exports和@H_723_435@module.exports的一个引用:

    console.log(exports === module.exports);	//true
    
    exports.foo = 'bar';
    
    //等价于
    module.exports.foo = 'bar';
    
    @H_450_5@当给exports重新赋值后࿰c;exports!= module.exports.

    @H_450_5@最终return的是module.exports,无论exports中的成员是什么都没用。

    真正去使用的时候:
    	导出单个成员:exports.xxx = xxx;
    	导出多个成员:module.exports 或者 modeule.exports = {};
    

    总结

    // 引用服务
    var http = require('http');
    var fs = require('fs');
    // 引用模板
    var template = require('art-template');
    // 创建服务
    var server = http.createServer();
    // 公共路径
    var wwwDir = 'D:/app/www';
    server.on('Request', function (req, res) {
        var url = req.url;
        // 读取文件
        fs.readFile('./template-apche.html', function (err, data) {
            if (err) {
                return res.end('404 Not Found');
            }
            fs.readdir(wwwDir, function (err, files) {
                if (err) {
                    return res.end('Can not find www Dir.')
                }
                // 使用模板引擎解析替换data中的模板字符串
                // 去xmpTempleteList.html中编写模板语法
                var htmlStr = template.render(data.toString(), { 
                    title: 'D:/app/www/ 的索引',
                    files:files 
                });
                // 发送响应数据
                res.end(htmlStr);
            })
        })
    });
    server.listen(3000, function () {
        console.log('Running....');
    })
    
    1.jQuery中的each 和 原生JavaScript方法forEach的区别:
    	提供源头:
        	原生js是es5提供的(不兼容IE8,
            jQuery的each是jQuery第三方库提供的(如果要使用需要用2以下的版本也就是1.版本),它的each方法主要用来遍历jQuery实例对象(伪数组),同时也可以做低版本forEach的替代品,jQuery的实例对象不能使用forEach方法࿰c;如果想要使用必须转为数组([].slice.call(jQuery实例对象))才能使用
    2.模块中导出多个成员和导出单个成员
    3.301302的区别:
    	301永久重定向,浏览器会记住
        302临时重定向
    4.exports和module.exports的区别:
    	每个模块中都有一个module对象
        module对象中有一个exports对象
        我们可以把需要导出的成员都挂载到module.exports接口对象中
    	也就是`@H_509_1032@module.exports.xxx = xxx`的方式
        但是每次写太多了就很麻烦࿰c;所以Node为了简化代码࿰c;就在每一个模块中都提供了一个成员叫`exports`
        `exports === module.exports`结果为true,所以完全可`exports.xxx = xxx`
        当一个模块需要导出单个成员的时候必须使用`@H_509_1032@module.exports = xxx`的方式࿰c;=,使用`exports = xxx`不管用,因为每个模块最终return的是module.exports,而exports只是module.exports的一个引用,所以`exports`即使重新赋值,也不会影响`@H_509_1032@module.exports`。
        有一种赋值方式比较特殊:`exports = module.exports`这个用来新建立引用关系的。
        
    

    4. require的加载规则

    • @H_450_5@核心模块

      • 模块名
    • @H_450_5@第三方模块

      • 模块名
    • @H_450_5@用户自己写的

      • 路径

    require的加载规则:

    • @H_450_5@优先从缓存加载

    • @H_450_5@判断模块标识符

      • 核心模块
      • 自己写的模块(路径形式的模块)
      • 第三方模块(node_modules)
        • 第三方模块的标识就是第三方模块的名称(不可能有第三方模块和核心模块的名字一致)
        • npm
          • 开发人员可以把写好的框架库发布到npm上
          • 使用者通过npm命令来下载
        • 使用方式:var 名称 = require('npm install【下载包】 的包名')
          • node_modules/express/package.json main
          • 如果package.json或者main不成立࿰c;则查找被选择项:index.js
          • 如果以上条件都不满足࿰c;则继续进入上一级目录中的node_modules按照上面的规则依次查找࿰c;直到当前文件所属此盘根目录都找不到最后报错
    // 如果非路径形式的标识
    // 路径形式的标识:
        // ./  当前目录 不可省略
        // ../  上一级目录  不可省略
        //  /xxx也就是D:/xxx
        // 带有绝对路径几乎不用(D:/a/foo.js)
    // 首位表示的是当前文件模块所属磁盘根目录
    // require('./a'); 
    
    
    // 核心模块
    // 核心模块本质也是文件࿰c;核心模块文件已经被编译到了二进制文件中了࿰c;我们只需要按照名字来加载就可以了
    require('fs'); 
    
    // 第三方模块
    // 凡是第三方模块都必须通过npm下载(npm i node_modules)࿰c;使用的时候就可以通过require('包名')来加载才可以使用
    // 第三方包的名字不可能和核心模块的名字是一样的
    // 既不是核心模块࿰c;也不是路径形式的模块
    //      先找到当前文所述目录的node_modules
    //      然后找node_modules/art-template目录
    //      node_modules/art-template/package.json
    //      node_modules/art-template/package.json中的main属性
    //      main属性记录了art-template的入口模块
    //      然后加载使用这个第三方包
    //      实际上最终加载的还是文件
    
    //      如果package.json不存在或者mian指定的入口模块不存在
    //      则node会自动找该目录下的index.js
    //      也就是说index.js是一个备选项࿰c;如果main没有指定࿰c;则加载index.js文件
    //      
            // 如果条件都不满足则会进入上一级目录进行查找
    // 注意:一个项目只有一个node_modules࿰c;放在项目根目录中࿰c;子目录可以直接调用根目录的文件
    var template = require('art-template');
    
    

    模块标识符中的/和文件操作路径中的/

    @H_450_5@文件操作路径:

    // 咱们所使用的所有文件操作的API都是异步的
    // 就像ajax请求一样
    // 读取文件
    // 文件操作中 ./ 相当于当前模块所处磁盘根目录
    // ./index.txt    相对于当前目录
    // /index.txt    相对于当前目录
    // /index.txt   绝对路径,当前文件模块所处根目录
    // d:express/index.txt   绝对路径
    fs.readFile('./index.txt',function(err,data){
        if(err){
           return  console.log('读取失败');
        }
        console.log(data.toString());
    })
    
    @H_450_5@模块操作路径:

    // 在模块加载中࿰c;相对路径中的./不能省略
    // 这里省略了.也是磁盘根目录
    require('./index')('hello')
    

    5. npm

    • node package manage(node包管理器)
    • 通过npm命令安装jQuery包(npm install --save jquery)࿰c;在安装时加上–save会主动生成说明书文件信息(将安装文件的信息添加到package.json里面)

    npm网站

    @H_450_5@​ npmjs.com 网站 是用来搜索npm包的

    npm命令行工具

    @H_450_5@npm是一个命令行工具࿰c;只要安装了node就已经安装了npm。

    @H_450_5@npm也有版本概念࿰c;可以通过npm --version来查看npm的版本

    @H_450_5@升级npm(自己升级自己):

    npm install --global npm
    

    常用命令

    • npm init(生成package.json说明书文件)
      • npm init -y(可以跳过向导࿰c;快速生成)
    • npm install
      • 一次性把dependencies选项中的依赖项全部安装
      • 简写(npm i)
    • npm install 包名
      • 只下载
      • 简写(npm i 包名)
    • npm install --save 包名
      • 下载并且保存依赖项(package.json文件中的dependencies选项)
      • 简写(npm i 包名)
    • npm uninstall 包名
      • 只删除࿰c;如果有依赖项会依然保存
      • 简写(npm un 包名)
    • npm uninstall --save 包名
      • 删除的同时也会把依赖信息全部删除
      • 简写(npm un 包名)
    • npm Help
      • 查看使用帮助
    • npm 命令 --Help
      • 查看具体命令的使用帮助(npm uninstall --Help)

    解决npm被墙问题

    @H_450_5@npm存储包文件的服务器在国外࿰c;有时候会被墙࿰c;速度很慢c;所以需要解决这个问题。

    @H_450_5@https://developer.aliyun.com/mirror/NPM?from=tnpm淘宝的开发团队把npm在国内做了一个镜像(也就是一个备份)。

    @H_450_5@安装淘宝的cnpm:

    npm install -g cnpm --registry=https://registry.npm.taobao.org;
    
    #在任意目录执行都可以
    #--global表示安装到全局࿰c;而非当前目录
    #--global不能省略࿰c;否则不管用
    npm install --global cnpm
    
    @H_450_5@安装包的时候把以前的npm替换成cnpm

    #走国外的npm服务器下载jQuery包࿰c;速度比较慢
    npm install jQuery;
    
    #使用cnpm就会通过淘宝的服务器来下载jQuery
    cnpm install jQuery;
    
    @H_450_5@如果不想安装cnpm又想使用淘宝的服务器来下载:

    npm install jquery --registry=https://npm.taobao.org;
    
    @H_450_5@但是每次手动加参数就很麻烦࿰c;所以我们可以把这个选项加入到配置文件中:

    npm config set registry https://npm.taobao.org;
    
    #查看npm配置信息
    npm config list;
    
    @H_450_5@只要经过上面的配置命令࿰c;则以后所有的npm install都会通过淘宝的服务器来下载

    6. package.json

    @H_450_5@每一个项目都要有一个package.json文件(包描述文件࿰c;就像产品的说明书一样)

    @H_450_5@这个文件可以通过npm init自动初始化出来

    
    D:codenode中的模块系统>npm init
    This utility will walk you through creaTing a package.json file.
    It only covers the most common items, and tries to guess sensible defaults.
    
    See `npm Help json` for definitive documentation on these fields
    and exactly what they do.
    
    Use `npm install <pkg>` afterWARDs to install a package and
    save it as a dependency in the package.json file.
    
    Press ^C at any time to quit.
    package name: (node中的模块系统)
    Sorry, name can only contain URL-friendly characters.
    package name: (node中的模块系统) cls
    version: (1.0.0)
    description: 这是一个测试项目
    entry point: (@H_626_629@main.js)
    test command:
    git repository:
    keywords:
    author: xiaochen
    license: (ISC)
    About to write to D:codenode中的模块系统package.json:
    
    {
      "name": "cls",
      "version": "1.0.0",
      "description": "这是一个测试项目",
      "main": "main.js",
      "scripts": {
        "test": "echo "Error: no test specified" && exit 1"
      },
      "author": "xiaochen",
      "license": "ISC"
    }
    
    
    Is this OK? (yes) yes
    
    @H_450_5@对于目前来讲࿰c;最有用的是dependencies选项࿰c;可以用来帮助我们保存第三方包的依赖信息。

    @H_450_5@如果node_modules删除了也不用担心࿰c;只需要在控制面板中npm install就会自动把package.json中的dependencies中所有的依赖项全部都下载回来。

    • 建议每个项目的根目录下都有一个package.json文件
    • 建议执行npm install 包名的时候都加上--save选项࿰c;目的是用来保存依赖信息

    package.json和package-lock.json

    @H_450_5@npm 5以前是不会有package-lock.json这个文件

    @H_450_5@npm5以后才加入这个文件

    @H_450_5@当你安装包的时候࿰c;npm都会生成或者更新package-lock.json这个文件

    • npm5以后的版本安装都不要加--save参数࿰c;它会自动保存依赖信息
    • 当你安装包的时候࿰c;会自动创建或者更新package-lock.json文件
    • package-lock.json这个文件会包含node_modules中所有包的信息(版本࿰c;下载地址。。。)
      • 这样的话重新npm install的时候速度就可以提升
    • 从文件来看࿰c;有一个lock称之为锁
      • 这个lock使用来锁版本的
      • 如果项目依赖了1.1.1版本
      • 如果你重新install其实会下载最细版本࿰c;而不是1.1.1
      • package-lock.json的另外一个作用就是锁定版本号࿰c;防止自动升级

    path路径操作模块

    @H_450_5@参文档:https://nodejs.org/docs/latest-v13.x/api/path.html

    • path.basename:获取路径的文件名࿰c;默认包含扩展名
    • path.dirname:获取路径中的目录部分
    • path.extname:获取一个路径中的扩展名部分
    • path.parse:把路径转换为对象
      • root:根路径
      • dir:目录
      • base:包含后缀名的文件名
      • ext:后缀名
      • name:不包含后缀名的文件名
    • path.join:拼接路径
    • path.isAbsolute:判断一个路径是否为绝对路径[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ERa4PXdZ-1630228376843)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200315150610001.png)]

    7. Node中的其它成员(__dirname,__fileName)

    @H_450_5@在每个模块中࿰c;除了require,exports等模块相关的API之外࿰c;还有两个特殊的成员:

    • @H_450_5@__dirnamec;是一个成员࿰c;可以用来动态获取当前文件模块所属目录的绝对路径

    • @H_450_5@__filenamec;可以用来动态获取当前文件的绝对路径(包含文件名)

    • @H_450_5@__dirnamefilename是不受执行node命令所属路径影响的

      @H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aMSBfDuF-1630228376845)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200315151551873.png)]

    @H_450_5@在文件操作中࿰c;使用相对路径是不可靠的࿰c;因为node中文件操作的路径被设计为相对于执行node命令所处的路径。

    @H_450_5@所以为了解决这个问题࿰c;只需要把相对路径变为绝对路径(绝对路径不受任何影响)就可以了。

    @H_450_5@就可以使用__dirname或者__filename来帮助我们解决这个问题

    @H_450_5@在拼接路径的过程中࿰c;为了避免手动拼接带来的一些低级错误࿰c;推荐使用path.join()来辅助拼接

    var fs = require('fs');
    var path = require('path');
    
    // console.log(__dirname + 'a.txt');
    // path.join方法会将文件操作中的相对路径都统一的转为动态的绝对路径
    fs.readFile(path.join(__dirname + '/a.txt'),'utf8',function(err,data){
    	if(err){
    		throw err
    	}
    	console.log(data);
    });
    
    @H_450_5@补充:模块中的路径标识和这里的路径没关系࿰c;不受影响(就是相对于文件模块)

    @H_450_5@注意:

    @H_450_5@模块中的路径标识和文件操作中的相对路径标识不一致

    @H_450_5@模块中的路径标识就是相对于当前文件模块࿰c;不受node命令所处路径影响

    8. Express(快速的)

    @H_450_5@作者:Tj

    @H_450_5@原生的http在某些方面表现不足以应对我们的开发需求࿰c;所以就需要使用框架来加快我们的开发效率࿰c;框架的目的就是提高效率࿰c;让我们的代码高度统一。

    @H_450_5@在Node中有很多web开发框架。主要学习express

    • @H_450_5@http://expressjs.com/,其中主要封装的是http

    • // 1 安装
      // 2 引包
      var express = require('express');
      // 3 创建服务器应用程序
      //      也就是原来的http.createServer();
      var app = express();
      
      // 公开指定目录
      // 只要通过这样做了c;就可以通过/public/xx的方式来访问public目录中的所有资源
      // 在Express中开放资源就是一个API的事
      app.use('/public/',express.static('/public/'));
      
      //模板引擎在Express中开放模板也是一个API的事
      
      // 当服务器收到get请求 / 的时候࿰c;执行回调处理函数
      app.get('/',function(req,res){
          res.send('Hello express');
      })
      
      // 相当于server.listen
      app.listen(3000,function(){
          console.log('app is runing at port 3000');
      })
      

    学习Express

    起步

    安装:
    @H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IDfpgV4Q-1630228376847)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200310123723079.png)]

    cnpm install express
    
    Hello world:
    @H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vUGcoqri-1630228376850)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200310124850557.png)]

    // 引入express
    var express = require('express');
    
    // 1. 创建app
    var app = express();
    
    //  2. 
    app.get('/',function(req,res){
        // 1
        // res.write('hello');
        // res.write('World');
        // res.end()
    
        // 2
        // res.end('Hello world');
    
        // 3
        res.send('Hello world');
    })
    
    app.listen(3000,function(){
        console.log('express app is runing...');
    })
    
    基本路由
    @H_450_5@路由:

    • @H_450_5@请求方法

    • @H_450_5@请求路径

    • @H_450_5@请求处理函数

    @H_450_5@get:

    //当你以get方法请求/的时候࿰c;执行对应的处理函数
    app.get('/',function(req,res){
        res.send('Hello world');
    })
    
    @H_450_5@post:

    //当你以post方法请求/的时候࿰c;执行对应的处理函数
    app.post('/',function(req,res){
        res.send('Hello world');
    })
    
    Express静态服务API
    // app.use不仅仅是用来处理静态资源的࿰c;还可以做很多工作(body-parser的配置)
    app.use(express.static('public'));
    
    app.use(express.static('files'));
    
    app.use('/stataic',express.static('public'));
    
    // 引入express
    var express = require('express');
    
    // 创建app
    var app = express();
    
    // 开放静态资源
    // 1.当以/public/开头的时候࿰c;去./public/目录中找对应资源
    // 访问:http://127.0.0.1:3000/public/login.html
    app.use('/public/',express.static('./public/')); 
    
    // 2.当省略第一个参数的时候࿰c;可以通过省略/public的方式来访问
    // 访问:http://127.0.0.1:3000/login.html
    // app.use(express.static('./public/'));   
    
    // 3.访问:http://127.0.0.1:3000/a/login.html
    // a相当于public的别名
    // app.use('/a/',express.static('./public/')); 
    
    //  
    app.get('/',function(req,res){
        res.end('Hello world');
    });
    
    app.listen(3000,function(){
        console.log('express app is runing...');
    });
    
    在Express中配置使用art-templete模板引擎
    • art-template官方文档
    • 在Node中࿰c;有很多第三方模板引擎都可以使用࿰c;不是只有art-template
      • 还有ejs࿰c;jade(pug)࿰c;handlebars࿰c;nunjucks
    @H_450_5@安装:

    npm install --save art-template
    npm install --save express-art-template
    
    //两个一起安装
    npm i --save art-template express-art-template
    
    @H_450_5@配置:

    app.@R_674_10846@ne('html', require('express-art-template'));
    
    @H_450_5@使用:

    app.get('/',function(req,res){
        // express默认会去views目录找index.html
        res.render('index.html',{
               title:'Hello world'     
        });
    })
    
    @H_450_5@如果希望修改默认的views视图渲染存储目录࿰c;可以:

    // 第一个参数views千万不要写错
    app.set('views',目录路径);
    
    在Express中获取表单请求数据
    获取get请求数据:
    @H_450_5@Express内置了一个api࿰c;可以直接通过req.query来获取数据

    // 通过requery方法获取用户输入的数据
    // req.query只能拿到get请求的数据
     var comment = req.query;
    
    获取post请求数据:
    @H_450_5@在Express中没有内置获取表单post请求体的api࿰c;这里我们需要使用一个第三方包body-parser来获取数据。

    @H_450_5@安装:

    npm install --save body-parser;
    
    @H_450_5@配置:

    @H_450_5@// 配置解析表单 POST 请求体插件(注意:一定要在 app.use(router) 之前 )

    var express = require('express')
    // 引包
    var bodyParser = require('body-parser')
    
    var app = express()
    
    // 配置body-parser
    // 只要加入这个配置࿰c;则在req请求对象上会多出来一个属性:body
    // 也就是说可以直接通过req.body来获取表单post请求数据
    // parse application/x-www-form-urlencoded
    app.use(bodyParser.urlencoded({ extended: false }))
    
    // parse application/json
    app.use(bodyParser.json())
    
    @H_450_5@使用:

    app.use(function (req, res) {
      res.setHeader('Content-Type', 'text/plain')
      res.write('you posted:n')
      // 可以通过req.body来获取表单请求数据
      res.end(JSON.Stringify(req.body, null, 2))
    })
    

    在Express中配置使用express-session插件操作

    @H_450_5@参文档:https://github.com/expressjs/session

    @H_450_5@安装:

    npm install express-session
    
    @H_450_5@配置:

    //该插件会为req请求对象添加一个成员:req.session默认是一个对象
    //这是最简单的配置方式
    //Session是基于Cookie实现的
    app.use(session({
      //配置加密字符串࿰c;他会在原有的基础上和字符串拼接起来去加密
      //目的是为了增加安全性࿰c;防止客户端恶意伪造
      secret: 'keyboard cat',
      resave: false,
      saveUninitialized: true,//无论是否适用Session࿰c;都默认直接分配一把钥匙
      cookie: { secure: true }
    }))
    
    @H_450_5@使用:

    // 读
    //添加Session数据
    //session就是一个对象
    req.session.foo = 'bar';
    
    //写
    //获取session数据
    req.session.foo
    
    //删
    req.session.foo = null;
    delete req.session.foo
    
    @H_450_5@提示:

    @H_450_5@默认Session数据时内存储数据࿰c;服务器一旦重启࿰c;真正的生产环境会把Session进行持久化存储。

    利用Express实现ADUS项目

    模块化思想

    @H_450_5@模块如何划分:

    • 模块职责要单一
    @H_450_5@javascript模块化:

    • Node 中的 CommonJS
    • 浏览器中的:
      • AMD require.js
      • CMD sea.js
    • es6中增加了官方支持

    起步

    • 初始化
    • 模板处理

    路由设计

    @H_450_462@@H_450_462@@H_450_462@@H_450_462@@H_450_462@@H_450_462@@H_450_462@
    请求方法请求路径get参数post参数备注
    GET/students渲染首页
    GET/students/new渲染添加学生页面
    POST/students/newname,age,gender,hobbies处理添加学生请求
    GET/students/editid渲染编辑页面
    POST/students/editid,name,age,gender,hobbies处理编辑请求
    GET/students/deleteid处理删除请求

    提取路由模块

    @H_450_5@router.js:

    /**
     * router.js路由模块
     * 职责:
     *      处理路由
     *      根据不同的请求方法+请求路径设置具体的请求函数
     * 模块职责要单一࿰c;我们划分模块的目的就是增强代码的可维护性࿰c;提升开发效率
     */
    var fs = require('fs');
    
    // Express专门提供了一种更好的方式
    // 专门用来提供路由的
    var express = require('express');
    // 1 创建一个路由容器
    var router = express.Router();
    // 2 把路由都挂载到路由容器中
    
    router.get('/students', function(req, res) {
        // res.send('Hello world');
        // readFile的第二个参数是可选的࿰c;传入utf8就是告诉他把读取到的文件直接按照utf8编码࿰c;直接转成我们认识的字符
        // 除了这样来转换࿰c;也可以通过data.toString()来转换
        fs.readFile('./db.json', 'utf8', function(err, data) {
            if (err) {
                return res.status(500).send('Server error.')
            }
            // 读取到的文件数据是String类型的数据
            // console.log(data);
            // 从文件中读取到的数据一定是字符串࿰c;所以一定要手动转换成对象
            var students = JSON.parse(data).students;
            res.render('index.html', {
                // 读取文件数据
                students:students
            })
        })
    });
    
    router.get('/students/new',function(req,res){
        res.render('new.html')
    });
    
    router.get('/students/edit',function(req,res){
        
    });
    
    router.post('/students/edit',function(req,res){
        
    });
    
    router.get('/students/delete',function(req,res){
        
    });
    
    // 3 把router导出
    module.exports = router;
    
    
    @H_450_5@app.js:

    var router = require('./router');
    
    // router(app);
    // 把路由容器挂载到app服务中
    // 挂载路由
    app.use(router);
    

    设计操作数据的API文件模块

    @H_450_5@es6中的find和findIndex:

    @H_450_5@find接受一个方法作为参数࿰c;方法内部返回一个条件

    @H_450_5@find会便利所有的元素࿰c;执行你给定的带有条件返回值的函数

    @H_450_5@符合该条件的元素会作为find方法的返回值

    @H_450_5@如果遍历结束还没有符合该条件的元素࿰c;则返回undefined[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8EVjZMlw-1630228376851)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200313103810731.png)]

    /**
     * student.js
     * 数据操作文件模块
     * 职责:操作文件中的数据࿰c;只处理数据࿰c;不关心业务
     */
    var fs = require('fs');
     /**
      * 获取所有学生列表
      * return []
      */
    exports.find = function(){
        
    }
    
    
     /**
      * 获取添加保存学生
      */
    exports.save = function(){
            
    }
    
    /**
     * 更新学生
     */
    exports.update = function(){
            
    }
    
     /**
     * 删除学生
     */
    exports.delete = function(){
            
    }
    

    步骤

    • @H_450_5@处理模板

    • @H_450_5@配置静态开放资源

    • @H_450_5@配置模板引擎

    • @H_450_5@简单的路由࿰c;/studens渲染静态页出来

    • @H_450_5@路由设计

    • @H_450_5@提取路由模块

    • @H_450_5@由于接下来的一系列业务操作都需要处理文件数据࿰c;所以我们需要封装student.js’

    • @H_450_5@先写好student.js文件结构

      • 查询所有学生列别哦的API
      • findById
      • save
      • updateById
      • deleteById
    • @H_450_5@实现具体功能

      • 通过路由收到请求
      • 接受请求中的参数(get࿰c;post)
        • req.query
        • req.body
      • 调用数据操作API处理数据
      • 根据操作结果给客户端发送请求
    • @H_450_5@业务功能顺序

      • 列表
      • 添加
      • 编辑
      • 删除

    子模板和模板的继承(模板引擎高级语法)【include࿰c;extend࿰c;block】

    @H_450_5@注意:

    @H_450_5@模板页:

    <!DOCTYPE html>
    <html lang="zh">
    <head>
    	<@H_626_629@meta charset="UTF-8">
    	<@H_626_629@meta name="viewport" content="width=device-width, initial-scale=1.0">
    	<@H_626_629@meta http-equiv="X-UA-Compatible" content="ie=edge">
    	<title>模板页</title>
    	<link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.css"/>
    	{{ block 'head' }}{{ /block }}
    </head>
    <body>
    	<!-- 通过include导入公共部分 -->
    	{{include './header.html'}}
    	
    	<!-- 留一个位置 让别的内容去填充 -->
    	{{ block  'content' }}
    		<h1>默认内容</h1>
    	{{ /block }}
    	
    	<!-- 通过include导入公共部分 -->
    	{{include './footer.html'}}
    	
    	<!-- 公共样式 -->
    	<script src="/node_modules/jquery/dist/jquery.js" ></script>
    	<script src="/node_modules/bootstrap/dist/js/bootstrap.js" ></script>
    	{{ block 'script' }}{{ /block }}
    </body>
    </html>
    
    @H_450_5@模板的继承:

    @H_450_5@​ header页面:

    <div id="">
    	<h1>公共的头部</h1>
    </div>
    
    @H_450_5@​ footer页面:

    <div id="">
    	<h1>公共的底部</h1>
    </div>
    
    @H_450_5@模板页的使用:

    <!-- 继承(extend:延伸࿰c;扩展)模板也layout.html -->
    <!-- 把layout.html页面的内容都拿进来作为index.html页面的内容 -->
    {{extend './layout.html'}}
    
    <!-- 向模板页面填充新的数据 -->
    <!-- 填充后就会替换掉layout页面content中的数据 -->
    <!-- style样式方面的内容 -->
    {{ block 'head' }}
    	<style type="text/css">
    		body{
    			BACkground-color: skyblue;
    		}
    	</style>
    {{ /block }}
    {{ block 'content' }}
    	<div id="">
    		<h1>Index页面的内容</h1>
    	</div>
    {{ /block }}
    <!-- js部分的内容 -->
    {{ block 'script' }}
    	<script type="text/javascript">
    		
    	</script>
    {{ /block }}
    
    @H_450_5@最终的显示效果:

    @H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f5WIFaUD-1630228376852)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200316134759517.png)]

    9. MongoDB

    关系型和非关系型数据库

    关系型数据库(表就是关系࿰c;或者说表与表之间存在关系)。

    • 所有的关系型数据库都需要通过sql语言来操作
    • 所有的关系型数据库在操作之前都需要设计表结构
    • 而且数据表还支持约束
      • 唯一的
      • 主键
      • 默认值
      • 非空

    非关系型数据库

    • 非关系型数据库非常的灵活
    • 有的关系型数据库就是key-value对儿
    • 但MongDB是长得最像关系型数据库的非关系型数据库
      • 数据库 -》 数据库
      • 数据表 -》 集合(数组)
      • 表记录 -》文档对象
    @H_450_5@一个数据库中可以有多个数据库࿰c;一个数据库中可以有多个集合(数组)࿰c;一个集合中可以有多个文档(表记录)

    {
        qq:{
           user:[
               {},{},{}...
           ]
        }
    }
    
    • 也就是说你可以任意的往里面存数据࿰c;没有结构性这么一说

    安装

    • @H_450_5@下载

    • @H_450_5@安装

      npm i mongoose
      
    • @H_450_5@配置环境变量

    • @H_450_5@最后输入@H_723_435@mongod --version测试是否安装成功

    启动和关闭数据库

    @H_450_5@启动:

    # mongodb 默认使用执行mongod 命令所处盼复根目录下的/data/db作为自己的数据存储目录
    # 所以在第一次执行该命令之前先自己手动新建一个 /data/db
    mongod
    
    @H_450_5@如果想要修改默认的数据存储目录࿰c;可以:

    @H_723_435@mongod --dbpath = 数据存储目录路径
    
    @H_450_5@停止:

    在开启服务的控制台࿰c;直接Ctrl+C;
    或者直接关闭开启服务的控制台。
    
    @H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lq9R7bnx-1630228376853)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200314101047100.png)]

    连接数据库

    @H_450_5@连接:

    # 该命令默认连接本机的 MongoDB 服务
    mongo
    
    @H_450_5@退出:

    # 在连接状态输入 exit 退出连接
    exit
    
    @H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eozyzkE8-1630228376855)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200314100821112.png)]

    基本命令

    • show dbs
      • 查看数据库列表(数据库中的所有数据库)
    • db
      • 查看当前连接的数据库
    • use 数据库名称
      • 切换到指定的数据库࿰c;(如果没有会新建)
    • show collections
      • 查看当前目录下的所有数据表
    • db.表名.find()

    在Node中如何操作MongoDB数据库

    使用官方的@H_723_435@mongoDB包来操作

    @H_450_5@​ http://mongodb.github.io/node-mongodb-native/

    使用第三方包@H_723_435@mongoose来操作MongoDB数据库

    @H_450_5@​ 第三方包:@H_723_435@mongoose基于MongoDB官方的@H_723_435@mongodb包再一次做了封装࿰c;名字叫@H_723_435@mongoose࿰c;是WordPress项目团队开发的。

    @H_450_5@​ https://mongoosejs.com/

    @H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nJ2y2y9R-1630228376856)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200314105632745.png)]

    @H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T0jnSXF8-1630228376857)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200314105717993.png)]

    学习指南(步骤)

    @H_450_5@官方学习文档:https://mongoosejs.com/docs/index.html

    设计scheR_515_11845@e 发布Model (创建表)

    // 1.引包
    // 注意:按照后才能require使用
    var mongoose = require('mongoose');
    
    // 拿到scheR_515_11845@a图表
    var scheR_515_11845@a = mongoose.scheR_515_11845@a;
    
    // 2.连接数据库
    // 指定连接数据库后不需要存在࿰c;当你插入第一条数据库后会自动创建数据库
    mongoose.connect('mongodb://localhost/test');
    
    // 3.设计集合结构(表结构)
    // 用户表
    var userscheR_515_11845@a = new scheR_515_11845@a({
    	username: { //姓名
    		type: String,
    		require: true //添加约束࿰c;保证数据的完整性࿰c;让数据按规矩统一
    	},
    	password: {
    		type: String,
    		require: true
    	},
    	email: {
    		type: String
    	}
    });
    
    // 4.将文档结构发布为模型
    // mongoose.model方法就是用来将一个架构发布为 model
    // 		第一个参数:传入一个大写名词单数字符串用来表示你的数据库的名称
    // 					mongoose 会自动将大写名词的字符串生成 小写复数 的集合名称
    // 					例如 这里会变成users集合名称
    // 		第二个参数:架构
    // 	返回值:模型构造函数
    var User = mongoose.@H_814_756@model('user', userscheR_515_11845@a);
    

    添加数据(增)

    // 5.通过模型构造函数对User中的数据进行操作
    var user = new User({
    	username: 'admin',
    	password: @R_675_6879@23456',
    	email: 'xiaochen@qq.com'
    });
    
    user.save(function(err, ret) {
    	if (err) {
    		console.log('保存失败');
    	} else {
    		console.log('保存成功');
    		console.log(ret);
    	}
    });
    

    删除(删)

    @H_450_5@根据条件删除所有:

    User.remove({
    	username: 'xiaoxiao'
    }, function(err, ret) {
    	if (err) {
    		console.log('删除失败');
    	} else {
    		console.log('删除成功');
    		console.log(ret);
    	}
    });
    
    @H_450_5@根据条件删除一个:

    @H_723_435@model.findOneAndRemove(conditions,[options],[callBACk]);
    
    @H_450_5@根据id删除一个:

    User.findByIdAndRemove(id,[options],[callBACk]);
    

    更新(改)

    @H_450_5@更新所有:

    User.remove(conditions,doc,[options],[callBACk]);
    
    @H_450_5@根据指定条件更新一个:

    User.FindOneAndupdate([conditions],[update],[options],[callBACk]);
    
    @H_450_5@根据id更新一个:

    // 更新	根据id来修改表数据
    User.findByIdAndupdate('5e6c5264fada77438c45dfcd', {
    	username: 'junjun'
    }, function(err, ret) {
    	if (err) {
    		console.log('更新失败');
    	} else {
    		console.log('更新成功');
    	}
    });
    

    查询(查)

    @H_450_5@查询所有:

    // 查询所有
    User.find(function(err,ret){
    	if(err){
    		console.log('查询失败');
    	}else{
    		console.log(ret);
    	}
    });
    
    @H_450_5@条件查询所有:

    // 根据条件查询
    User.find({ username:'xiaoxiao' },function(err,ret){
    	if(err){
    		console.log('查询失败');
    	}else{
    		console.log(ret);
    	}
    });
    
    @H_450_5@条件查询单个:

    // 按照条件查询单个࿰c;查询出来的数据是一个对象({})
    // 没有条件查询使用findOne方法࿰c;查询的是表中的第一条数据
    User.findOne({
    	username: 'xiaoxiao'
    }, function(err, ret) {
    	if (err) {
    		console.log('查询失败');
    	} else {
    		console.log(ret);
    	}
    });
    

    10. 使用Node操作MySQL数据库

    @H_450_5@文档:https://www.npmjs.com/package/mysql

    @H_450_5@安装:

    npm install --save  mysql
    
    // 引入mysql包
    var mysql      = require('mysql');
    
    // 创建连接
    var connection = mysql.createConnection({
      host     : @R_674_3384@host',	//本机
      user     : 'me',		//账号root
      password : 'secret',	//密码12345
      database : 'my_db'	//数据库名
    });
     
    // 连接数据库	(打开冰箱门)
    connection.connect();
     
    //执行数据操作	(把大象放到冰箱)
    connection.query('SELECT * FROM `users` ', function (error, results, fields) {
      if (error) throw error;//抛出异常阻止代码往下执行
      // 没有异常打印输出结果
      console.log('The solution is: ',results);
    });
    
    //关闭连接	(关闭冰箱门)
    connection.end();
    

    异步编程

    回调函数

    @H_450_5@不成立的情况下:

    function add(x,y){
        console.log(1);
        setTimeout(function(){
            console.log(2);
            var ret = x + y;
            return ret;
        },1000);
        console.log(3);
        //到这里执行就结束了࿰c;不会i等到前面的定时器࿰c;所以直接返回了默认值 undefined
    }
    
    console.log(add(2,2));
    // 结果是 1 3 undefined 4
    
    @H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x6NLOQ65-1630228376858)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200313085008929.png)]

    @H_450_5@使用回调函数解决:

    @H_450_5@回调函数:通过一个函数࿰c;获取函数内部的操作。(根据输入得到输出结果)

    var ret;
    function add(x,y,callBACk){
        // callBACk就是回调函数
        // var x = 10;
        // var y = 20;
        // var callBACk = function(ret){Console.log(ret);}
        console.log(1);
        setTimeout(function(){
            var ret = x + y;
            callBACk(ret);
        },1000);
        console.log(3);
    }
    add(10,20,function(ret){
        console.log(ret);
    });
    
    Node.js b站教学视频汇总笔记(完)CommonJS模块规范、 require、npm、Express(中间件)、MongoDB、MySQL @H_450_5@注意:

    @H_450_5@​ 凡是需要得到一个函数内部异步操作的结果(setTimeout,readFile,writeFile,ajax,readdir)

    @H_450_5@​ 这种情况必须通过 回调函数 (异步API都会伴随着一个回调函数)

    @H_450_5@ajax:

    @H_450_5@基于原生XMLhttprequest封装get方法:

    var oReq = new XMLhttprequest();
    // 当请求加载成功要调用指定的函数
    oReq.onload = function(){
        console.log(oReq.responseText);
    }
    oReq.open("GET", "请求路径",true);
    oReq.send();
    
    function get(url,callBACk){
        var oReq = new XMLhttprequest();
        // 当请求加载成功要调用指定的函数
        oReq.onload = function(){
            //console.log(oReq.responseText);
            callBACk(oReq.responseText);
        }
        oReq.open("GET", url,true);
        oReq.send();
    }
    get('data.json',function(data){
        console.log(data);
    });
    

    Promise

    @H_450_5@callBACk Hell(回调地狱):

    @H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XWH7qzin-1630228376859)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200314143410972.png)]

    @H_450_5@文件的读取无法判断执行顺序(文件的执行顺序是依据文件的大小来决定的)(异步api无法保证文件的执行顺序)

    var fs = require('fs');
    
    fs.readFile('./data/a.text','utf8',function(err,data){
    	if(err){
    		// 1 读取失败直接打印输出读取失败
    		return console.log('读取失败');
    		// 2 抛出异常
    		// 		阻止程序的执行
    		// 		把错误信息打印到控制台
    		throw err;
    	}
    	console.log(data);
    });
    
    fs.readFile('./data/b.text','utf8',function(err,data){
    	if(err){
    		// 1 读取失败直接打印输出读取失败
    		return console.log('读取失败');
    		// 2 抛出异常
    		// 		阻止程序的执行
    		// 		把错误信息打印到控制台
    		throw err;
    	}
    	console.log(data);
    });
    
    @H_450_5@通过回调嵌套的方式来保证顺序:

    var fs = require('fs');
    
    fs.readFile('./data/a.text','utf8',function(err,data){
    	if(err){
    		// 1 读取失败直接打印输出读取失败
    		return console.log('读取失败');
    		// 2 抛出异常
    		// 		阻止程序的执行
    		// 		把错误信息打印到控制台
    		throw err;
    	}
    	console.log(data);
    	fs.readFile('./data/b.text','utf8',function(err,data){
    		if(err){
    			// 1 读取失败直接打印输出读取失败
    			return console.log('读取失败');
    			// 2 抛出异常
    			// 		阻止程序的执行
    			// 		把错误信息打印到控制台
    			throw err;
    		}
    		console.log(data);
    		fs.readFile('./data/a.text','utf8',function(err,data){
    			if(err){
    				// 1 读取失败直接打印输出读取失败
    				return console.log('读取失败');
    				// 2 抛出异常
    				// 		阻止程序的执行
    				// 		把错误信息打印到控制台
    				throw err;
    			}
    			console.log(data);
    		});
    	});
    });
    
    @H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GZWbpddG-1630228376860)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200314144807008.png)]为了解决以上编码方式带来的问题(回调地狱嵌套)࿰c;所以在EcmaScript6新增了一个API:Promise。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ctFL5g3S-1630228376861)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200314150050839.png)]

    • Promise:承诺࿰c;保证
    • Promise本身不是异步的࿰c;但往往都是内部封装一个异步任务
    @H_450_5@基本语法:

    // 在EcmaScript 6中新增了一个API Promise
    // Promise 是一个构造函数
    
    var fs = require('fs');
    // 1 创建Promise容器		resolve:解决   reject:失败
    var p1 = new Promise(function(resolve, reject) {
    	fs.readFile('./a.text', 'utf8', function(err, data) {
    		if (err) {
    			// console.log(err);
    			// 把容器的Pending状态变为rejected
    			reject(err);
    		} else {
    			// console.log(data);
    			// 把容器的Pending状态变为resolve
    			resolve(1234);
    		}
    	});
    });
    
    // 当p1成功了࿰c;然后就(then)做指定的操作
    // then方法接收的function就是容器中的resolve函数
    p1
    	.then(function(data) {
    		console.log(data);
    	}, function(err) {
    		console.log('读取文件失败了', err);
    	});
    
    
    @H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lNRvC9GN-1630228376861)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200315100611620.png)]

    @H_450_5@链式循环:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iI4RLzkz-1630228376862)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200315125559136.png)]

    @H_450_5@封装Promise的readFile

    var fs = require('fs');
    
    function pReadFile(filePath) {
    	return new Promise(function(resolve, reject) {
    		fs.readFile(filePath, 'utf8', function(err, data) {
    			if (err) {
    				reject(err);
    			} else {
    				resolve(data);
    			}
    		});
    	});
    }
    
    pReadFile('./a.txt')
    	.then(function(data) {
    		console.log(data);
    		return pReadFile('./b.txt');
    	})
    	.then(function(data) {
    		console.log(data);
    		return pReadFile('./a.txt');
    	})
    	.then(function(data) {
    		console.log(data);
    	})
    
    
    @H_450_5@mongoose所有的API都支持Promise:

    // 查询所有
    User.find()
    	.then(function(data){
            console.log(data)
        })
    
    @H_450_5@注册:

    User.findOne({username:'admin'},function(user){
        if(user){
            console.log('用户已存在')
        } else {
            new User({
                 username:'aaa',
                 password:@R_675_6879@23',
                 email:'fffff'
            }).save(function(){
                console.log('注册成功');
            })
        }
    })
    
    User.findOne({
        username:'admin'
    })
        .then(function(user){
            if(user){
                // 用户已经存在不能注册
                console.log('用户已存在');
            }
            else{
                // 用户不存在可以注册
                return new User({
                    username:'aaa',
                    password:@R_675_6879@23',
                    email:'fffff'
                }).save();
            }
        })
        .then(funciton(ret){
    		console.log('注册成功');
        })
    

    Generator

    @H_450_5@async函数

    11. 其他

    修改完代码自动重启

    @H_450_5@我们在这里可以使用一个第三方命名行工具:nodemon来帮助我们解决频繁修改代码重启服务器的问题。

    @H_450_5@nodemon是一个基于Node.js开发的一个第三方命令行工具࿰c;我们使用的时候需要独立安装:

    #在任意目录执行该命令都可以
    #也就是说࿰c;所有需要 --global安装的包都可以在任意目录执行
    npm install --global nodemon
    npm install -g nodemon
    
    #如果安装不成功的话࿰c;可以使用cnpm安装
    cnpm install -g nodemon
    
    @H_450_5@安装完毕之后使用:

    node app.js
    
    #使用Nodemon
    nodemon app.js
    
    @H_450_5@只要是通过nodemon启动的服务࿰c;则他会监视你的文件变化࿰c;当文件发生变化的时候࿰c;会自动帮你重启服务器。

    封装异步API

    @H_450_5@回调函数:获取异步操作的结果

    function fn(callBACk){
        // var callBACk = funtion(data){ console.log(data); }
    	setTimeout(function(){
            var data = 'hello';
            callBACk(data);
        },1000);
    }
    // 如果需要获取一个函数中异步操作的结果࿰c;则必须通过回调函数的方式来获取
    fn(function(data){
        console.log(data);
    })
    

    数组的遍历方法࿰c;都是对函数作为一种参数

    @H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oiG3ap1H-1630228376863)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200314094620191.png)]

    EcmaScript 6

    @H_450_5@参文档:https://es6.ruanyifeng.com/

    12. 项目案例

    目录结构

    .
    app.js	项目的入口文件
    controllers
    models	存储使用mongoose设计的数据模型
    node_modules	第三方包
    package.json	包描述文件
    package-lock.json	第三方包版本锁定文件(npm5之后才有)
    public	公共静态资源
    routes
    views	存储视图目录
    

    模板页

    • 子模板
    • 模板继承

    路由设计

    @H_450_462@@H_450_462@@H_450_462@@H_450_462@@H_450_462@@H_450_462@@H_450_462@@H_450_462@
    路由方法get参数post参数是否需要登录备注
    /get渲染首页
    /register(登录)get渲染注册页面
    /registerpostemail,nickname,password处理注册请求
    /loginget渲染登陆界面
    /loginpostemail,password处理登录请求
    /loginoutget处理退出请求

    模型设计

    功能实现

    步骤

    • 创建目录结构
    • 整合静态也-模板页
      • include
      • block
      • extend
    • 设计用户登陆࿰c;退出࿰c;注册的路由
    • 用户注册
      • 先处理客户端页面的内容(表单控件的name࿰c;收集表单数据࿰c;发起请求)
      • 服务端
        • 获取从客户端收到的数据
        • 操作数据库
          • 如果有错࿰c;发送500告诉客户端服务器错了‘
          • 其他的根据业务发送不同的响应数据
    • 登录
    • 退出

    13. Express中间件

    中间件的概念

    @H_450_5@参文档:http://expressjs.com/en/guide/using-middleware.html

    @H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JsOS7jNs-1630228376864)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200316202757617.png)]

    @H_450_5@中间件:把很复杂的事情分割成单个࿰c;然后依次有条理的执行。就是一个中间处理环节࿰c;有输入࿰c;有输出。

    @H_450_5@说的通俗易懂点儿࿰c;中间件就是一个(从请求到响应调用的方法)方法。

    @H_450_5@把数据从请求到响应分步骤来处理࿰c;每一个步骤都是一个中间处理环节。

    var http = require('http');
    var url = require('url');
    
    var cookie = require('./expressPtoject/cookie');
    var query = require('./expressPtoject/query');
    var postBody = require('./expressPtoject/post-body');
    
    var server = http.createServer(function(){
    	// 解析请求地址中的get参数
    	// var obj = url.parse(req.url,truE);
    	// req.query = obj.query;
    	query(req,res);	//中间件
    	
    	// 解析请求地址中的post参数
    	req.body = {
    		foo:'bar'
    	}
    });
    
    if(req.url === 'xxx'){
    	// 处理请求
    	...
    }
    
    server.listen(3000,function(){
    	console.log('3000 runing...');
    });
    
    @H_450_5@同一个请求对象所经过的中间件都是同一个请求对象和响应对象。

    var express = require('express');
    var app = express();
    app.get('/abc',function(req,res,next){
    	// 同一个请求的req和res是一样的࿰c;
    	// 可以前面存储下面调用
    	console.log('/abc');
    	// req.foo = 'bar';
    	req.body = {
    		name:'xiaoxiao',
    		age:18
    	}
    	next();
    });
    app.get('/abc',function(req,res,next){
    	// console.log(req.foo);
    	console.log(req.body);
    	console.log('/abc');
    });
    app.listen(3000, function() {
    	console.log('app is running at port 3000.');
    });
    
    
    @H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Reh90kg0-1630228376875)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200317110520098.png)]

    中间件的分类:

    应用程序级别的中间件

    @H_450_5@万能匹配(不关心任何请求路径和请求方法的中间件):

    app.use(function(req,res,next){
        console.log('Time',Date.now());
        next();
    });
    
    @H_450_5@关心请求路径和请求方法的中间件:

    app.use('/a',function(req,res,next){
        console.log('Time',Date.now());
        next();
    });
    

    路由级别的中间件

    @H_450_5@严格匹配请求路径和请求方法的中间件

    @H_450_5@get:

    app.get('/',function(req,res){
    	res.send('get');
    });
    
    @H_450_5@post:

    app.post('/a',function(req,res){
    	res.send('post');
    });
    
    @H_450_5@put:

    app.put('/user',function(req,res){
    	res.send('put');
    });
    
    @H_450_5@delete:

    app.delete('/delete',function(req,res){
    	res.send('delete');
    });
    

    var express = require('express');
    var app = express();
    
    // 中间件:处理请求࿰c;本质就是个函数
    // 在express中࿰c;对中间件有几种分类
    
    // 1 不关心任何请求路径和请求方法的中间件
    // 也就是说任何请求都会进入这个中间件
    // 中间件本身是一个方法࿰c;该方法接收三个参数
    // request 请求对象
    // Response 响应对象
    // next 下一个中间件
    // // 全局匹配中间件
    // app.use(function(req, res, next) {
    // 	console.log('1');
    // 	// 当一个请求进入中间件后
    // 	// 如果需要请求另外一个方法则需要使用Next()方法
    // 	next();
    // 	// next是一个方法࿰c;用来调用下一个中间件
    //  // 注意:next()方法调用下一个方法的时候࿰c;也会匹配(不是调用紧挨着的哪一个)
    // });
    // app.use(function(req, res, next) {
    // 	console.log('2');
    // });
    
    // // 2 关心请求路径的中间件
    // // 以/xxx开头的中间件
    // app.use('/a',function(req, res, next) {
    // 	console.log(req.url);
    // });
    
    // 3 严格匹配请求方法和请求路径的中间件
    app.get('/',function(){
    	console.log('/');
    });
    app.post('/a',function(){
    	console.log('/a');
    });
    
    app.listen(3000, function() {
    	console.log('app is running at port 3000.');
    });
    
    

    错误处理中间件

    app.use(function(err,req,res,next){
        console.error(err,stack);
        res.status(500).send('Something broke');
    });
    
    @H_450_5@配置使用404中间件:

    app.use(function(req,res){
        res.render('404.html');
    });
    
    @H_450_5@配置全局错误处理中间件:

    app.get('/a', function(req, res, next) {
    	fs.readFile('.a/bc', funtion() {
    		if (err) {
            	// 当调用next()传参后࿰c;则直接进入到全局错误处理中间件方法中
            	// 当发生全局错误的时候࿰c;我们可以调用next传递错误对象
            	// 然后被全局错误处理中间件匹配到并进行处理
    			next(err);
    		}
    	})
    });
    //全局错误处理中间件
    app.use(function(err,req,res,next){
        res.status(500).json({
            err_code:500,
            message:err.message
        });
    });
    

    内置中间件

    • express.static(提供静态文件)
      • http://expressjs.com/en/starter/static-files.html#serving-static-files-in-express

    第三方中间件

    @H_450_5@参文档:http://expressjs.com/en/resources/middleware.html

    • body-parser
    • compression
    • cookie-parser
    • @H_401_11@mogran
    • response-time
    • server-static
    • session

大佬总结

以上是大佬教程为你收集整理的Node.js b站教学视频汇总笔记(完)CommonJS模块规范、 require、npm、Express(中间件)、MongoDB、MySQL全部内容,希望文章能够帮你解决Node.js b站教学视频汇总笔记(完)CommonJS模块规范、 require、npm、Express(中间件)、MongoDB、MySQL所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。