开源与跨平台的 JavaScript 运行时环境
运行于单个进程中,无需为每个请求创建新的线程
异步I/O、非阻塞。执行 I/O 操作时(例如从网络读取、访问数据库或文件系统),Node.js 会在响应返回时恢复操作,而不是阻塞线程并浪费 CPU 循环等待。——> 高并发
# 什么是 Node.js
# 官方定义
- Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。
- Node.js 使用了一个事件驱动、非阻式I/O 的模型,使其轻量且高效。
# Node.js 中与 Chrome 中写 JS 有什么区别
- Node.js 没有浏览器 API,即 document、window 等
- 加入了许多 Node.js API
- Chrome 中写 JS 控制浏览器,Node.js 中写 JS 控制整个计算机
# Node.js 好在哪
# 在处理高并发、I/O 密集场景性能优势明显
CPU 密集:压缩、解压、加密、解密、运算
I/O 密集:文件操作、网络操作、数据库读写
web 常见场景:
- 静态资源读取
- 数据库操作
- 渲染页面
高并发应对之道:
- 增加机器数
- 增加每台机器的 CPU 数 —— 多核
Node.js 的单线程
- 单线程只是针对主进程,操作系统底层的多线程调度来完成 I/O
- 单线程并不是单进程
# Node.js 可以用来做什么
# 现阶段应用领域
- web 服务中间层 - web server
- 构建工作流 - 本地代码构建(属于cpu密集,从性能考虑并不适合node来做,但因为前端熟悉js)
- 实用小工具开发 - 脚本工具、爬虫等
- 客户端应用
# web 服务中间层
# 实例
腾讯视频
# 原因
- 搜索引擎优化 + 首屏加速 = 服务端渲染
- 服务端渲染 + 前后端同构 = Node.js
# 构建工作流
# 实例
- gulp
- webpack
# 原因
- 前端构建工具是为了构建前端代码 = 使用对象是前端开发
- 功能需要扩展、问题需要修复 = 前端开发看得懂、能解决 = Node.js
# 客户端应用
# 实例
- VS Code
- 游戏 - wayward
# 原因
使用 Node.js 的客户端技术 Electron
# 安装(3m安装法)
# nvm( node 版本安装及管理工具 )
安装 nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.1/install.sh | bash
查看可安装node版本
nvm ls-remote
安装node
nvm install 14.15.1
nvm install 8
查看本机已安装版本
nvm ls
切换版本
nvm use 14.15.1
指定默认版本
切换到目标版本后
nvm alias default node
重新安装全局模块
通过某个版本node自带的npm安装的全局模块,仅能在当前版本node环境使用,若要使node v14.15.1上安装的全局模块在其它node版本中共用,可执行
nvm reinstall-packages 14.15.1
# npm( nodejs 包下载工具)
安装npm
因为npm本身也是一个Node.js模块,所以可以通过 npm 来安装
npm install -g npm@2.9
常用选项
无选项
安装到 node_module ,但不保存到 package.json--global/-g
安装到全局,如果是命令行模块,会直接链接到环境变量里--save/-S
安装 node_module ,并保存在 package.json 里的 dependencies ,表示生产环境依赖的模块--save-dev/-D
安装 node_module ,并保存在 package.json 里的 devDependencies ,表示开发环境依赖的模块
# nrm( npm 镜像源切换)
安装
npm install -g nrm
因为是命令行模块,所以需要全局安装查看源
nrm ls
npm、cnpm、yarn、taobao等测速
nrm test
切换源
nrm use cnpm
增加源
为了保证开发效率,企业在内网部署一套私有 npm 源是非常有必要的。推荐使用 cnpm 部署私有源镜像服务器。
nrm add 自定义指令名 企业镜像地址
# Node.js 基础
# 什么是技术预研
- 分析要做的需求,找出技术难点
- 针对每个技术难点进行攻克
# BFF 层
即 Backend For Frondend,就是前端和服务端之间的中间渲染层
- 对用户侧提供 HTTP 服务
- 使用后端 RPC(Romote Procedure Call远程过程调用) 服务
# 模块:CommonJS 规范
# 的问题
- 脚本变多时,需要手动管理加载顺序
- 不同脚本之间逻辑调用,需要通过全局变量的方式
- 没有 html 安放 script 怎么办?例如 nodejs 中就没有 html
# CommonJS 模块规范
- 每个文件是一个模块,有自己的作用域
- 模块内部 module 变量代表模块本身
- module.exports 属性代表模块对外接口
待整理:规范、exports与module.exports、webpack打包出来的文件
exports 是 module.exports 的快捷方式,common.js 中对外暴露的永远都是module.exports,而exports只是它的引用,所以不能直接给exports赋值,因为赋值会修改exports的指向,只能exports.xx = xx 这样挂载的方式使用。
# require特性
- module 被加载时执行,加载后缓存
- 循环加载时,只输出已执行的部分,还未执行的部分不会输出
# global
- commonjs
- buffer、process、console
- timer
- process.nextTick 放入当前事件队列的队尾,setImmediate 放入下一个队列的队首,setTimeout 介于两者之间
# path
- __dirname、__filename 总是返回文件的绝对路径
- process.cwd() 总是返回执行 node 命令所在的文件夹
# ./
- 在 require 的参数中总是相对当前文件所在的文件夹
- 在其它地方和 process.cwd() 一样,相对 node 启动文件夹
# Buffer
- 用来处理二进制数据流
- 实例类似整数数组,大小固定,默认16进制表示
- 利用C++代码在V8堆外分配物理内存
# 内置模块
负责nodejs的应用层面到操作系统层面的通信,包括nodejs调用操作系统的能力或者说操作系统通知nodejs的能力。有了内置模块,nodejs就具有了强大的和操作系统交互的能力,从而可以做出服务端应用的能力。
TODO: 内置模块运行机制 极客时间《Node.js开发实战》12-Node.js内置模块
# 异步:非阻塞I/O
I/O 即 Input/Output,一个系统的输入和输出
阻塞 I/O 和非阻塞 I/O 的区别就在于系统接收输入再到输出期间,能不能接收其它输入。
nodejs 线程通过事件循环调度其它 C++ 线程来异步处理任务,实现了整个 nodejs 的非阻塞 I/O。
# 异步:异步编程之 callback
回调函数规范:error-first callback,即第一个参数是error,后面的参数才是结果。
# 异步流程控制
常见恶心场景:
- 回调地狱;
- 并行执行
# 事件循环
代码模拟:
const eventloop = {
queue: [],
loop() {
while (this.queue.length) {
const callback = this.queue.shift()
callback()
}
setTimeout(this.loop.bind(this), 50)
},
add(callback) {
this.queue.push(callback)
}
}
eventloop.loop()
setTimeout(() => {
eventloop.add(() => {
console.log(1)
})
}, 500)
setTimeout(() => {
eventloop.add(() => {
console.log(2)
})
}, 800)
# 异步:异步编程之Promise
当前的事件循环得不到的结果,但未来的事件循环会给到你结果。
执行 then 和 catch 会返回一个新的 Promise,该 Promise 最终状态根据 then 和 catch 的回调函数的执行结果决定:
- 如果回调函数最终是 throw,该 Promise 是 rejected 状态
- 如果回调函数最终是 return,该 Promise 是 resolved 状态
- 如果回调函数最终 return 了一个 Promise,该 Promise 会和回调函数 return 的 Promise 状态保持一致
# 异步:异步编程之async/await
- 本质是 Promise 的语法糖
- 异步编程的终极解决方案 - 以同步的方式写异步
- await 关键字可以“暂停” async function 后边代码的执行
- await 关键字可以以同步的写法获取 Promise 的执行结果
- try-catch 可以获取 await 所得到的错误 - 一个穿越 事件循环而存在的 functio n
# ES6+知识点
# 生成器 Generator
返回一个迭代器,每个迭代器都有 next 方法,用来获取每次迭代生成的对象
node 模块 co 就是利用了 generator