前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版

Node基础篇回顾 从HTTP模块到Express与MongoDB

首页2019-03-09 17:40:43Back-End
JavaScriptNodeExpressMongoDB

前端做久了总会碰到这么一天,后端说接口下周才能给,你想自己起个服务把假数据顶上;或者要写个脚本批量重命名两千张切图;再或者面试官冷不丁问一句「你说说 Node 的非阻塞 I/O 到底非阻塞在哪」。这三件事考的其实是同一块知识,就是 Node 的那几个基础模块和它背后的运行模型。

这篇是我当年过 Node 基础时留下的复习笔记,后来又整理了一遍。它不讲花哨的架构,只把 http、url、fs、CommonJS、npm、Express、MongoDB 这几块从头串一遍,代码都能直接跑。读完你至少能自己起一个带路由、带模板、带数据库读写的完整服务,也能把 Cookie 和 Session 的区别讲明白。

在本篇文章中,我们将从浅入深,和大家一起学习以下知识:

  • Node 是什么,它凭什么能扛住高并发,以及它真正适合的场景
  • 用 http + url 模块手写一个能识别路径的服务器,配 supervisor 做热重启
  • CommonJS 模块化规范,exports 和 module.exports 的区别
  • npm 与 package.json,dependencies 和 devDependencies 怎么分
  • fs 模块的文件读写、目录操作、流与管道
  • 非阻塞 I/O、事件驱动、回调与 events 模块
  • Express 的安装、路由、EJS 模板、静态托管与五类中间件
  • Cookie、Session 的用法、加密与持久化落库
  • MongoDB 从安装到增删改查,再到索引和 explain 调优

# 一、Node.js 是什么

# 1.1 简介

先把最容易被绕晕的一点说清楚。Node 不是一门语言,也不是一个框架,它是一个 JavaScript 的运行环境。你平时写的 js 文件双击打不开,拖进浏览器才有效果,那是因为解释执行它的引擎长在浏览器里。Node 干的事情就是把那个引擎单独拎出来,放到操作系统上,再给它配一套操作文件、网络、进程的能力。

  • nodejs是一个JavaScript运行环境。它让 JavaScript 可以开发后端程序,实现几乎其他后端语言实现的所有功能
  • Nodejs 是基于 V8 引擎,V8 是 Google 发布的开源 JavaScript 引擎,本身就是用于 Chrome 浏览器 的 JS 解释部分, V8 搬到了服务器上,用于做服务器的软件
  • 短短几年的时间,Node 取得了巨大的成功。在企业界,Node 的应用也越来越广泛,2016 年 nodeJS 官方的调查报告。2016 年全球有 350 万开发者使用 nodeJS,相比去年保持了 100%的增长率。像 Yahoo、 Microsoft 这样的大公司,有好多应用已经迁移到 Node 了。国内的阿里巴巴、网易、腾讯、新浪、百度等 公司的很多线上产品也纷纷改用 Node 开发,并取得了很好的效果。据统计很多 A 轮、 B 轮的创业公司更 喜欢使用 NodeJs 开发。

https://nodejs.org/static/documents/2016-survey-report.pdf

这份 2016 年的调查报告是我写这篇笔记时手头能引到的官方数据,现在看数字已经很旧了,社区规模比那会儿大得多。不过它反映的趋势没变,Node 从一个「前端玩具」变成了公司里正经的服务端选项。

有件事得提一句。V8 本身只负责把 JavaScript 代码跑起来,它不带任何 I/O 能力,读文件、开端口这些活是 Node 通过 libuv 这一层补上的。所以准确说,Node 等于 V8 加 libuv 加一堆内置模块。搞清楚这个分层,后面聊非阻塞 I/O 的时候你就知道那个「异步」是谁提供的了。

# 1.2 NodeJs 的优势

1. NodeJs 语法完全是 js 语法,只要你懂 JS 基础就可以学会 Nodejs 后端开发

Node 打破了过去 JavaScript 只能在浏览器中运行的局面。前后端编程环境统一,可以大大降低开发成本

2. NodeJs 超强的高并发能力

  • Node.js 的首要目标是提供一种简单的、用于创建高性能服务器及可在该服务器中运行的各种应用程 序的开发工具
  • 首先让我们来看一下现在的服务器端语言中存在着什么问题。 在 Java、PHP 或者.net 等服务器端语言中,会为每一个客户端连接创建一个新的线程。而每个线程需要耗费大约 2MB 内存 理论上,一个 8GB 内存的服务器可以同时连接的最大用户数为 4000 个左右 。要让 Web 应用程序支持更多的用户,就 需要增加服务器的数量,而 Web 应用程序的硬件成本当然就上升了
  • Node.js 不为每个客户连接创建一个新的线程,而仅仅使用一个线程。当有用户连接了,就触发一个 内部事件,通过非阻塞 I/O、事件驱动机制,让 Node.js 程序宏观上也是并行的。使用 Node.js,一个 8GB 内存的服务器,可以同时处理超过 4 万用户的连接

3. 实现高性能服务器

  • 严格地说,Node.js 是一个用于开发各种 Web 服务器的开发工具。在 Node.js 服务器中,运行的是高性能 V8 JavaScript 脚本语言,该语言是一种可以运行在服务器端的 JavaScript 脚本语言
  • 那么,什么是 V8 JavaScript 脚本语言呢?该语言是一种被 V8 JavaScript 引擎所解析并执行的脚本语言。V8 JavaScript 引擎是由 Google 公司使用 C++语言开发的一种高性能 JavaScript 引擎,该引擎并不局限于在浏览 器中运行。Node.js 将其转用在了服务器中,并且为其提供了许多附加的具有各种不同用途的 API。例如, 在一个服务器中,经常需要处理各种二进制数据。在 JavaScript 脚本语言中,只具有非常有限的对二进制数 据的处理能力,而 Node.js 所提供的 Buffer 类则提供了丰富的对二进制数据的处理能力
  • 另外,在 V8 JavaScript引擎内部使用一种全新的编译技术,靠它开发者编写的高端的 JavaScript 脚本代码与开发者编写的低端的C语言具有非常相近的执行效率,这也是Node.js服务器可以提供的一个重要特性

4. 开发周期短、开发成本低、学习成本低。

  • Node.js 自身哲学,是花最小的硬件成本,追求更高的并发,更高的处理性能。
  • 特点:Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient.

上面这几段是当年很流行的说法,我得给它加个边界。「一个线程扛 4 万连接」成立的前提是这些连接大部分时间在等 I/O,比如等数据库、等下游接口、等文件读完。这种场景下 Node 的单线程根本没闲着,它在事件循环里来回切。

但反过来,只要你在请求处理里写了一段 CPU 密集的计算,比如同步的大数组排序、图片处理、复杂的加解密,那唯一的那条主线程就被你占死了,后面排队的所有请求全部卡住。

这是 Node 最经典的翻车姿势,而且线上不好复现。

现在的做法是把这类活丢给 worker_threads 或者单独的进程池,别在主线程里干。关于线上 Node 服务怎么部署、怎么用多进程把 CPU 核心吃满,我另外写过一篇 PM2 + Docker 部署 Node 应用,这里就不展开了。

# 1.3 NodeJs 适合做什么

在短短几年多的时间里,Node 变得非常热门,使用者也非常多。这些使用者对于 Node 的各自倚重点也各部相同,经过整理,主要有下几类

1. 前后端编程语言环境统一

这类重点的代表是雅虎。雅虎开放了 Cocktail 框架,利用 自己深厚的前端沉淀,将 YUI3 这个前端框架的能力借助 Node 延伸到服务器端,使得使用 者摆脱了日常工作中一边写 JavaScript 一边写 PHP 所带来的上下文交换负担

2. Node 带来的高性能 I/O 用于实时应用

Voxer 将 Node 应用在实时语音上。国内腾讯的 朋友网将 Node 应用在长连接中,以提供实时功能,花瓣网、蘑菇街等公司通过 socket.io 实 现实时通知的功能。

3. 并行 I/O 使得使用者可以更高效地利用分布式环境

阿里巴巴 eBay 是这方面的典型。 阿里巴巴的 NodeFox 和 eBay 的 ql.io 都是借用 Node 并行 I/O 的能力,更高效地使用已有的 数据

4. 并行 I/O 有效利用稳定接口提升 Web 渲染能力

雪球财经和 LinkedIn 的移动版网站均 是这种案例,摒弃同步等待式的顺序请求,大胆采用并行 I/O,加速数据的获取进而提升 Web 的渲染速度

5. 云计算平台提供 Node 支持

微软将 Node 引入 Azure 的开发中,阿里云、百度均纷纷 在云服务器上提供 Node 应用托管服务,Joyent 更是云计算中提供 Node 支持的代表。这类 平台看重 JavaScript 带来的开发上的优势,以及低资源占用、高性能的特点

6. 游戏开发领域

游戏领域对实时和并发有很高的要求,网易开源了 pomelo 实时框架, 可以应用在游戏和高实时应用中

7. 工具类应用

过去依赖 java 或其他语言构建的前端工具类应用,纷纷被一些前端工程 师用 Node 重写,用前端熟悉的语言为前端构建熟悉的工具

顺着上面聊,第七条是绝大多数前端最先用上 Node 的地方。webpack、Vite、ESLint、Prettier,你每天敲的 npm run dev 背后跑的都是 Node 进程。所以哪怕你不打算写服务端,把这些基础模块摸清楚,调构建工具的时候也会顺手很多。

# 二、HTTP 模块、URL 模块与 supervisor

用 Node.js 时,我们不仅仅在实现一个应用,同时还实现了整个 HTTP 服务器

这句话是理解 Node 服务端的关键。写 PHP 的时候你要装 Apache,写 Java 的时候你要部署 Tomcat,业务代码是跑在别人的容器里的。Node 不一样,端口监听、请求解析、响应写回,全是你自己代码里的几行。灵活是灵活了,代价是那些 Web 服务器帮你干的脏活,现在得你自己想。

# 2.1 创建一个简单的程序

先跑起来一个最小的 HTTP 服务,感受一下 Node 里「应用即服务器」是什么意思。

var http = require('http');

http.createServer(function(request, response) {
    // 发送 HTTP 头部
    // HTTP 状态值: 200 : OK
    // 设置 HTTP 头部,状态码是 200,文件类型是 html,字符集是 utf8
    response.writeHead(200, { "Content-Type": "text/html;charset=UTF-8" });
    // 发送响应数据
    response.end("哈哈哈哈,我买了一个 iPhone" + (1 + 2 + 3) + "s");
}).listen(8888);
// 终端打印如下信息
console.log('Server running at http://127.0.0.1:8888/');
@前端进阶之旅: 代码已经复制到剪贴板

存成 server.js,node server.js 跑起来,浏览器打开 http://127.0.0.1:8888/ 就能看到那句话。(1 + 2 + 3) 会被真的算成 6,说明返回给浏览器的内容是服务端现算出来的,不是一段静态文本。

这里有个坑要注意,charset=UTF-8 这段不能省。少了它,中文在部分浏览器里会变成一串问号,这个我踩过,排查了半天才发现是响应头的事,跟代码逻辑一点关系没有。

你会发现,我们本地写一个 js,打死都不能直接拖入浏览器运行,但是有了 node,我 们任何一个 js 文件,都可以通过 node 来运行。也就是说,node 就是一个 js 的执行环境

fe
  • 一、Node.js 是什么
    • 1.1 简介
    • 1.2 NodeJs 的优势
    • 1.3 NodeJs 适合做什么
  • 二、HTTP 模块、URL 模块与 supervisor
    • 2.1 创建一个简单的程序
    • 2.2 HTTP 模块、URL 模块
      • 2.2.1 HTTP 模块的使用
      • 2.2.2 URL 模块的使用
    • 2.3 Nodejs 自启动工具 supervisor
  • 三、CommonJS 与 Node 的模块化
    • 3.1 什么是 CommonJs
    • 3.2 Nodejs 中的模块化
      • 3.2.1 在 Node 中,模块分为两类
      • 3.2.2 CommonJS(Nodejs)中自定义模块的规定
      • 3.2.3 定义使用模块
  • 四、NPM 第三方模块与 package.json
    • 4.1 包与 NPM
      • 4.1.1 包
      • 4.1.2 NPM 介绍
    • 4.2 package.json
    • 4.3 安装淘宝镜像
  • 五、fs 模块与文件操作
    • 5.1 fs.stat 检测是文件还是目录
    • 5.2 fs.mkdir 创建目录
    • 5.3 fs.writeFile 创建写入文件
    • 5.4 fs.appendFile 追加文件
    • 5.5 fs.readFile 读取文件
    • 5.6 fs.readdir 读取目录
    • 5.7 fs.rename 重命名
    • 5.8 fs.rmdir 删除目录
    • 5.9 fs.unlink 删除文件
    • 5.10 fs.createReadStream 从文件流中读取数据
    • 5.11 fs.createWriteStream 写入文件
    • 5.12 管道流
  • 六、动手创建一个 Web 服务器
  • 七、非阻塞 I/O、异步与事件驱动
    • 7.1 Nodejs的单线程 非阻塞I/O事件驱动
    • 7.2 Nodejs 回调处理异步
    • 7.3 Nodejs events 模块处理异步
  • 八、静态文件托管、路由、GET POST 与 EJS 模板
    • 8.1 路由
    • 8.2 初识 EJS 模块引擎
    • 8.3 Get、Post
  • 九、MongoDB 介绍、安装与使用
    • 9.1 数据库和文件的主要区别
    • 9.2 NoSql 介绍
      • 9.2.1 NoSQL 介绍
      • 9.2.2 NoSQL 应用情况介绍
    • 9.3 什么时候建议使用 NoSql
    • 9.4 NoSql 和传统数据库简单对比
    • 9.5 NoSql 种类
    • 9.6 MongoDb 介绍
    • 9.7 MongoDb 安装
    • 9.8 使用 MongoDb
  • 十、MongoDB 数据库与集合的增删改查
    • 10.1 数据库使用
    • 10.2 创建数据库
    • 10.3 插入(增加)数据
    • 10.4 查找数据
    • 10.5 修改数据
    • 10.6 删除数据
  • 十一、MongoDB 索引与 explain 查询分析
    • 11.1 索引基础
    • 11.2 唯一索引
    • 11.3 索引的一些参数
    • 11.4 使用 explain
    • 11.5 explain executionStats 查询具体的执行 时间
  • 十二、Node 操作 MongoDB 3.x 的方法
  • 十三、用 Node 操作 MongoDB 增删改查
    • 13.1 在 Nodejs 中使用 Mongodb
    • 13.2 Nodejs 连接 MongoDb 数据库
    • 13.3 Nodejs 查找 MongoDb 数据库集合
    • 13.4 Nodejs 给 MongoDb 增加数据
    • 13.5 Nodejs 修改 MongoDb 数据
    • 13.6 Nodejs 删除 MongoDb 数据
  • 十四、Express 安装与使用
    • 14.1 Express 简单介绍
    • 14.2 Express 安装使用
    • 14.3 Express 框架中的路由
    • 14.4 Express 框架中 ejs 的安装使用
    • 14.5 利用 Express.static 托管静态文件
    • 14.6 Express 中间件
    • 14.7 获取 Get Post 请求的参数
  • 十五、Express 中间件之 Cookie
    • 15.1 Cookie 简介
    • 15.2 Cookie 特点
    • 15.3 Cookie 的使用
    • 15.4 加密 Cookie
  • 十六、Express 中间件之 express-session
    • 16.1 Session 简单介绍
    • 16.2 Session 的工作流程
    • 16.3 express-session 的使用
    • 16.4 express-session 的常用参数
    • 16.5 express-session 的常用方法
    • 16.6 负载均衡配置 Session,把 Session 保存到数据库 里面
    • 16.7 Cookie 和 Session 区别
  • 总结
  • 参考

← 重新认识Koa2,洋葱模型与ctx到底是怎么实现的Node.js系列之WebSocket与socket.io实战 →