Node.js简介
什么是Node.js?
Node.js不是一门语言,而是一个基于Google V8引擎,跨平台的JavaScript运行环境
Node.js安装与运行
Node.js在实际开发中使用偶数版本(长期维护版本)
⭐️Node.js应用举个简单的栗子
读取package.json内容
//index.js中
const {readFile} = require('fs');
//以‘utf-8’读取package.json,有错误抛出错误,没有错误console.log
readFile( './package.json ',{encoding: 'utf-8'}, (err,data)=>{
if(err){
throw err;
}
console.log(data);
})
\> `node index.js`
输出package.json文件内容
版本管理
-
如何快速切换Node.js版本
n:一个npm全局开源包,是依赖npm来全局安装、使用的
fnm:快速简单,兼容性支持.node-version和.nvmrc文件
nvm:独立的软件包,使用比较多
Node.js特点
-
异步I/O
当Node.js执行I/O操作(文件的读写,网络请求与读写等)时,会在响应返回恢复操作,而不是阻塞线程并浪费CPU循环等待
简单来说,当Node.js执行I/O操作然后在等待响应的时候,不会整个系统等待响应,中途还能干别的事,直到响应返回再恢复操作代码编写顺序和执行顺序无关
-
单线程
Node.js保持了JavaScript在浏览器中单线程的特点
👉优点:
不用处处在意状态同步问题,不会发现死锁
没有线程上下文切换带来的性能开销👉缺点:(解决方案在后)
无法引用多核CPI
错误会引起整个应用退出,健壮性不足
大量计算占用CPU无法继续执行⭐️ 举个栗子 浏览器是多进程,JS引擎单线程 Browser进程:浏览器主进程,只有一个 插件进程:插件使用时才创建 渲染进程:页面渲染、JS执行、事件处理 -
跨平台
主要得益于在操作系统与Node上层模块系统之间构建了一层平台架构 -
应用场景
Node.js在大部分领域都有一席之地,特别是I/O密集型例如: Web应用:Express/Koa 前端构建:Webpacks<br> GUI客户端软件:VSCode、网易云音乐... 其它:爬虫等...
模块化机制
何为模块化
根据功能或业务将一个大程序拆分成互相依赖的小文件,再用简单的方式拼装起来
为什么模块化?无模块化有什么问题?
1 .所有script标签必须保证顺序正确,否则会依赖报错
2. 全局变量存在命名冲突,占用内存无法回收
3. IIFE/namespace会导致代码可读性低等诸多问题...
CommonJS规范
Node.js支持CommonJS模块规范,采用同步机制加载模块
exports 和module.exports指向同一个地址
∴exports = module.exports = {}
加载方式
-
加载内置模块
require('fs') -
加载相对||绝对路径的文件模块
require('/User/.../file.js')
require('./file.js') -
加载npm包
require('lodash')⭐️npm包查找原则:require('lodash') 1. 当前目录node_modules 2. 如果没有,父级目录的node_modules 3. 如果没有,沿着路径向上递归,直到根目录下node_modules 4. 找到只会回家再package.json main指向的文件,如果没有package.json则依次查找index.js、index、json、index.node
require.cache
require.cache中由于同步加载缓存着加载过的模块
如果没有缓存,文件模块查找耗时增加。如果每次require都需要重新遍历查找,性能较差
⭐️如何删除require.cache
//有缓存
const mod1 = require('./foo');
const mod2 = require('./foo');
console.log( mod1 === mod2 );//true
//无缓存
function requireUncaches(module){
//删除require.cache
delete require.cache[require.resolve(module)];
return require(module);
}
const mod3 = requireUncaches('./foo');
console.log( mod1 === mod3 );//false
ESModules(简称ESM)
- ESM是在ES6语言层面提出的一种模块化标准
- ESM中主要有import、export两个关键词,不能console.log打印两个关键字
如何使用ESM
ESM是在模块在编译的时候输出(提前加载)
- node>=13:
在Node层面,后缀改为.mjs后直接编写,比如:node main.mjs
项目package.json中,添加<scrip>标签中添加type="module" - node<=12:
--experimental-modules
CommonJS VS ESM
-
CommonJS模块输出的是一个值的拷贝;ESM模块输出的是值的引用
-
CommonJS模块是运行时加载;ESM是在模块在编译的时候输出(提前加载)
CommonJS 和 ESM可以混用,但是最好不要!
其它模块化规范
| 名称 | 区别 |
|---|---|
| AMD | 异步加载,推崇依赖前置 |
| CMD | 异步加载,推崇就近依赖 |
| UMD | 兼容AMD和CommonJS模式 |
| ES Modules | 语言层面的模块化规范,与环境无关,可借助babel编译 |
⭐️模块化规范对应的环境
包管理机制
npm介绍
npm是Node.js中的包管理器,提供了安装、删除等命令来管理包
⭐️一些有关的介绍
- dependencies 业务依赖,应用发布后正常执行所需要的包
- devDependencies 开发依赖、只用于开发环境
- peerDependencies 同等依赖、比如一个webpack插件依赖特点版本的webpack
- bundledDependencies 打包依赖(npm run pack),必须已经在devDep或dep声明过
- optionalDependencies 可选依赖
私有npm
- 镜像公司内部私有
- 镜像设置 npm config set registry=url
其它
npm | yarn => lock/扁平/缓存...
pnpm => monorepo/硬、符号链接/安全性高...
异步编程
Callback
Promise
Promise是一个具有四个状态的有限状态机,其中三个核心状态为Pending(挂起),Fulfilled(完成)、Rejected(拒绝),以及还有一个未开始状态
⭐️使用Promise和Callback
!使用Callback有时会有一些很深的嵌套
!使用Promise可以使嵌套扁平化
如何将Callback转为Promise形式?
util.promisifh
await
await函数使用try、catch捕获异常(注意并行处理)
Event
发布订阅模式,Node.js内置events模块
比如HTTP sever on ('requests')事件监听
Web应用开发
Koa介绍
Koa——基于Node.js平台的下一代Web开发框架。它仅仅提供了一个轻量优雅的函数库,使编写Web应用变得得心应手,不在内核方法中绑定任何中间件
Koa执行过程
-服务启动
-实例化application
-注册中间件
-创建服务,监听端口
-接受/处理请求
-获取请求req,res对象
-req -> request、 req -> respose封装
-request&response -> context
-执行中间件
-输出设置到ctx.body上的内容
⭐️图示:
Koa中间件
Koa应用程序是一个包含一组中间件的函数对象,他是按照洋葱模型组织和执行的
Koa中间件繁多,质量参差不齐,需要合理选择,高效组合
⭐️一条请求在中间件的历经之路
基于Koa的前端框架
开源:ThinkJS/Egg...
内部:Turbo、E让、Gulu...
线上部署
Node.js基于事件驱动、异步非阻塞模式,可以用于高并发场景,同时避免了线程创建、线程上下文切换所产生的资源开销
⭐️解决上文中Node.js单线程造成的缺点方法:
- 利用多核CPU
Node.js提供了cluster/child_process模块 - 提高健壮性:
可以使用Node.js进程管理工具来守护进程,从而提高健壮性 - 复杂计算占用CPU卡住了怎么办
使用多进程与进程通信
!通过父进程监听子进程降低CPU卡住的可能性
最后
之前有学习使用过一些Node.js,通过这一次的系统学习,更加了解的服务端开发与前端开发的联系和区别。学习路漫漫,想成为一名合格的前端工程师,这些知识都是需要了解的,加油哇~
如果有任何不对的记录,欢迎指正~!~