前端思维导图
2023-03-27 17:22:39 1 举报
AI智能生成
为你推荐
查看更多
前端导图
作者其他创作
大纲/内容
DNS获取IP地址
建立TCP连接
建立HTTPS连接
建立HTTP连接
后端返回内容
页面渲染
输入 URL
通过link标签的dns-prefetch属性对项目中其他域名去预解析
CSS 雪碧图(合并)、base64(file-loader 转换)、选择webp、图片懒加载、预加载
代码压缩
路由懒加载
网络层面
组件合理拆分
利用 Template 的 block tree 特性
for 循环唯一 key
合理使用computed(lazy watch)
代码层面
class 代替频繁操作 style
批量操作dom
尽量使用 transform
重绘、回流
ETag
Last-Modified
协商缓存 (304)
etag优先级高,etag适用case:当修改了文件的修改时间时
Cache-Control
Expires
from memory cache(不请求网络资源,资源在内存当中,一般脚本、字体、图片会存在内存当中)
from disk cache(不请求网络资源,在磁盘当中,一般非脚本会存在内存当中,如css等)
强缓存(200 from cache)
缓存层面
顺序执行、并发加载
HTML 渲染过程特点
css haed 中阻塞页面的渲染(保证有样式,也就是说页面的渲染会等到 css加载完成)
css 阻塞js执行
css 不阻塞js加载
CSS阻塞
直接引入的 js 会阻塞页面的渲染
js 不阻塞资源的加载
js 顺序执行,阻塞后续js逻辑的执行
js 阻塞
页面渲染依赖css加载
js的执行顺序有依赖关系
js 逻辑对dom节点有依赖关系
依赖关系
直接引入(阻塞页面渲染)
defer(不阻塞页面渲染,按顺序执行)
async(不阻塞页面渲染,不按顺序执行)
异步动态引入js
js 引入方式
css 样式置顶
link 代替 @import
js 脚本置底
合理使用 js 的异步加载能力
策略
渲染层面
thread-loader(创建 worker pool 来多进程地对每个loader处理)
happypack 多进程处理 loader
优化解析时间
cache-loader
hardSourceWebpackPlugin
利用打包缓存
terser-webpack-plugin 启动多进程压缩优化代码
优化压缩时间
利用 loader 的test、include、exclude 等配置项
利用 resolve 的 alias、modules、extensions 等配置项
缩小搜索时间
url-loader 对小图片进行 base64 转换
雪碧图
减少请求次数
使用 externals 来避免第三方包打入到 verdor 中
使用懒加载(路由懒加载、组件懒加载)
tree shaking (lodash-es 包)
scope hoisting 作用域提升
html、css、js 压缩
减少包体积
optimization.splitChunks
miniCss 工具来提取 css 并配置 content-hash
利用浏览器缓存
打包层面
构建层面
SSR
FCP 首次渲染时间
TTI 页面可以开始交互的时间
LCP 页面中最大的图片或文本块渲染的时间
lighthouse
工具指标
性能优化
定位:静态模块打包工具
初始化参数:从配置文件、shell参数、配置对象中读取,与默认配置合并生成最终参数
初始化编译器对象:用上一步参数创建 Compiler 对象
初始化编译环境:包括注入内置插件、注册各种模块工厂、初始化 RuleSet 集合、加载配置的插件等
开始编译:执行 compiler 的 run 方法
确定入口:根据 entry 找出所有的入口文件,调用 compilituon.addEntry 将入口文件转换为 dependence 对象
初始化阶段
编译模块:根据 entry 对应的 dependence 创建 module 对象,loaders 逐个执行,将对应文件转译为有效模块。并调用 JS 解释器将其转化为 AST 对象,从中找到该模块依赖的模块,再递归处理。
完成模块编译:通过模块间的依赖关系,得到依赖关系图
构建阶段
输出资源:根据入口和模块之间的依赖关系,组装一个个包含多个模块的 chunk,再把每个 chunk 转换成一个单独的文件
在生成好输出内容后,根据配置的输出路径和文件名,把文件内容写入到文件系统
生成阶段
工作流程
在执行new Plugin() 的时候执行插件原型上的 apply 方法
通过进行钩子函数的监听来执行不同的操作(compiler.hooks.xxxx.tap)
场景:在 build 的时候生成一个 md 文件,统计打包的文件名和数量
自定义 plugin
场景:自定义 md-loader,渲染出 md 文件
自定义 loader
module(源码中的文件)
chunk(webpack构建时的文件)
bundle(输出后的文件)
entry(编译入口,webpack 编译的入口)
compiler(编译管理器,webpack启动后会创建一个 compiler 对象,该对象一直存在)
plugin(打包优化,资源管理,注入环境变量等)
loader(loader 用于转换某些类型的模块)
tapable(是 webpack 用来创建钩子的库,为 webpack 提供了插件接口的支柱)
hash(所有文件哈希值相同,只要改变内容跟之前的不一致,所有哈希值都改变,没有做到缓存意义)
chunkhash(同一个模块,就算将js和css分离,其哈希值也是相同的,修改一处,js和css哈希值都会变,同hash,没有做到缓存意义)
contenthash(只要文件内容不一样,产生的哈希值就不一样,抽离出的CSS文件可以使用)
名词概念
场景:微前端的公共模块拆分
模块联邦
webpack
对于依赖,使用 Esbuild 进行预构建
对于源码,利用浏览器ESM特性,让浏览器接管打包程序的部分工作,Vite 只需要在浏览器请求源码的时候进行转换输出
启动速度
对于源码模块会利用协商缓存
对于依赖模块会利用强缓存
webpack 的HMR还需要重新构建并重载页面,而 vite 因为没有经过 bundle,所以可以只替换编辑的文件即可
更新速度
嵌套导入带来额外的网络往返
打包可以带来 tree-shaking、懒加载、chunk 分割
为什么生产环境仍然需要打包(默认 rollup 进行生产构建,也是基于 ESM)
生态不如webpack
生产环境使用 rollup,可能会开发环境、生产环境不同
缺点
vite(bundle less)
工程化
技术栈无关
独立开发、独立部署
增量升级
独立运行时
定位
技术成熟
支持页面嵌入
自带沙箱隔离、独立运行
通讯机制孱弱
应用的加载、渲染、缓存可控性不足
页面可以不同域名带来鉴权问题
iframe
优势
劣势
支持自定义元素
支持 shadow dom
支持模板 template 和插槽 slot
接入时候需要对原项目进行重写
兼容性不好
web component
Single SPA及qiankun
利用 webpack5 的模块联邦进行模块共享
接入成本高、兼容性差
EMP
方案选择
webpack 的 output 中,libraryTarget: 'umd'
子应用需要支持 script、common.js、AMD 形式引用
webpack 的 devServer 中,增加 headers: { 'Access-Control-Allow-Origin': '*' }
子应用需要支持CORS
增加 bootstrap、mount、unmount 等钩子函数,并在 mount 中调用 render
子应用需要增加声明周期钩子函数供主应用调用
webpack 的 output 中,修改 jsonpFunction 配置一个自定义的名称(webpack5 中已移除)
防止多个子应用的全局变量冲突
快照沙箱:性能差,适用于老旧浏览器,只能单实例,即一个页面只能有一个子应用
代理沙箱:可以支持单实例、多实例,利用 proxy 实现
JS隔离
css modules
shadow dom
minicss
postcss-selector-namespace
css in js
CSS隔离
CustomEvent
props
通信
qiankun
微前端
进程是资源分配的最小单位
线程是CPU调度的最小单位
进程可以比作“火车”,线程可以比较“车厢”,即一个进程可以有多个线程,线程必须在进程中运行。
线程和进程
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构
Javascript 通常用 Map 结构进行代替,查询时间复杂度为 O(1)
哈希表
数组(Array)是有序的元素序列。
访问的时间复杂度O(1)、搜索的时间复杂度O(n)
数组
时间复杂度O(logn)
二叉树
数据结构
计算机相关
callback
设计 scheduler
设计 retry
event loop
手写 promise
手写 promise.all
手写 promise.race
promisify
promise
co函数
thunk 函数
generator
async await
异步
Child.prototype = new Parent()
所有属性会被实例共享,所以引用类型时候会有问题
创建子类实例时,不能传参
原型链继承
在Child类中 使用call或apply来调用Parent类
避免了引用类型被所有实例共享
可以通过子类向父类传参
不能访问父类的原型上方法和属性
构造函数继承(经典继承)
优点
组合继承是原型链继承和经典继承的双剑合璧。
父类的构造函数会执行两次
组合继承
和原型链继承一样,引用类型的属性会被所有的实例共享
原型式继承
和借用构造函数(经典继承)一样,每次创建对象都会把方法创建一遍
寄生式继承
理想继承
寄生组合继承
必须要调用 super(),才能继承父类
编译成一个IFFE自执行函数,内部通过 _createClass 对 class 里的方法进行循环处理,其内部通过 Object.defineProperty 将方法挂载到原型上
class 继承
继承
手写 call
手写 apply
手写 bind
手写 new
手写防抖
手写节流
手写 instanceof
shuffle
sort(小于10时是插入排序,否则为快排)
打乱顺序
手写
JS基础
Monorepo (更好的代码结构,社区的二次开发)
Typescript (开发维护)
源码优化
Vue2 时代的小程序框架 mpvue 就必须得 fork 一份Vue代码,修改 runtime 和 compiler 文件
包体积(移除API、Tree-shaking)
数据劫持 (Proxy 代替 Object.defineProperty)
Block-Tree
编译优化
优化逻辑组织
优化逻辑复用
Composition
API
Feature
Runtime + Compiler
Runtime only (借助 vue-loader)
分类
和Vue2不同之处:多了一个虚拟根节点,从而支持 Fragment
parse (Template => AST)
创建 transform 上下文
遍历 AST 节点(核心:处理各种指令、表达式等,并给每种节点打上标签)
静态提升 (每次 render 的时候可以重用之前的 VNode)
创建根代码生成节点
transform (AST 转换)
generate (AST => VNode)
过程
编译阶段(Template => VNode)
VNode => DOM (组件初始化的过程)
Vue2
Vue3
在Vue1中,因为依赖收集了全部数据的watcher,导致项目庞大时候的性能问题
在Vue2中,依赖收集仅仅收集了组件级别的render watcher,和用户设置的 user wacher(computed、watch),而组件内部的更新,是通过引入的虚拟dom的diff来处理,这样就极大减小了 wacher 的监听数量
React 中在 React16 之前通过 diff 对整个dom数进行diff比较,导致页面卡顿
React 16之后采用 fiber 机制来解决页面卡顿问题
对比React(或者问:为什么Vue不需要fiber架构)
响应式
同步头部节点
同步尾部节点
添加新增节点
删除多余节点
最长递增子序列
寻找最长递增子序列
处理未知子序列
处理剩余节点
Vue3 (利用编译阶段的BlockTree,来减少比对数量)
旧的首节点和新的首节点
旧的尾节点和新的尾节点
旧的首节点和新的尾节点
旧的尾节点和新的首节点
Vue2
diff (组件更新的过程中,新旧节点都是 vnode 数组时)
循环(双端比较)
原理
Provide/Inject
props/$emit
Vuex 等类状态管理
$parent/$children
自定义广播
eventBus
$ref
父子通信
teleport
组件的API形式调用
v-model 语法糖(props为 value,emit 为 input)
.sync 语法糖
nextTick
keep-alive(LRU)
观察者模式、发布-订阅模式
零碎知识点
Vue-Router
Vuex
插件
时间切片(本质还是模拟 requestIdleCallback)
优先级划分:根据用户对交互的预期顺序为交互产生的状态更新赋予不同的优先级
Scheduler(调度器)—— 调度任务的优先级,高优任务优先进入Reconciler
React15 中递归处理虚拟DOM
通过调用 shouldYield 判断当前是否还有剩余时间
React16 可以中断的循环处理
定义:React 内部实现的一套状态更新机制。支持任务不同优先级,可中断与恢复,并且恢复后可以复用之前的中间状态
架构层面:Fiber 调和器
return (父节点)
child (子节点)
sibling (兄弟节点)
数据结构:Fiber 结构 类似于链表结构
更新任务单元:Fiber 保存了本次更新中该组件改变的状态、要执行的工作
工作原理:双缓存
与JSX 的区别
Fiber
同级比较
不同的类型元素直接替换更新,不比较内部
设置 key 来更大化复用
预设条件
递增法 —— 找递增子序列 O(m*n)
key 与 index 构成一个Map O(n)
diff
Reconciler(协调器)—— 负责找出变化的组件(为变化的虚拟DOM打上标记,当所有组件都完成Reconciler的工作,才会统一交给 Renderer)
Renderer(渲染器)—— 负责将变化的组件渲染到页面上
架构
有其他更高优先任务需要先更新
当前帧没有剩余时间
会被中断
只有在生命周期函数中、React的合成事件中,才会触发令 isBatchingUpdate 为 true
同步or异步
setState
修改 DOM ,改变布局就用 useLayoutEffect ,其他情况就用 useEffect 。
useEffect 和 useLayoutEffect
React.forwardRef
抹平各浏览器间的兼容问题
跨平台
性能(相当于事件委托)
合成事件(绑定的事件会冒泡到document处,然后交由专门的处理函数处理)
事件系统
触发时机:this.setState、this.forceUpdate、ReactDOM.render
更新机制
React
框架
浏览器进程
该域名下的所有页面共享一个
渲染进程
GPU进程
网络进程
插件进程
页面至少有4个进程
网络层 IP 协议 (IP头:传送到目标主机)
三次握手
四次挥手
TCP头:数据可靠、具有重发机制
UDP头:快、不可靠、无重发机制
传输层 TCP/UDP 协议(传送到目标应用程序)
连接持久化,减少TCP的连接和断开次数
每个域名下可同时维护6个TCP持久连接
Cookie 和 安全机制
队头阻塞
慢启动
多条TCP连接竞争带宽
http1.1
对发起HTTP请求的数据进行加密
对接收的HTTP数据进行解密操作
作用
浏览器向服务器发送对称加密套件列表、非对称加密套件列表、客户端随机数
服务器向浏览器发送对称加密套件、非对称加密套件、服务端随机数、公钥
浏览器生成新的随机数,并用公钥加密发送给服务器
服务器用自己的私钥对接收的随机数进行解密,并返回确认消息
至此,浏览器和服务器端都有了三个随机数,就可以以此生成对称秘钥
采用非对称+对称加密
用非对称加密的方法对对称加密的秘钥进行加密
在TCP和HTTP之间增加SSL/TLS安全层
网站向 CA 机构提交公钥、公司、站点等信息并等待认证
认证成功后,CA会向网站下发数字证书,包含公钥及公司相关信息
数字证书的申请
浏览器和系统都会内置一些根证书,当浏览器收到服务端发送的数字证书会查看证书链里是否包含根证书,如果没找到,则通过中间证书向上继续找
验证签名是否可信
比如 证书中包含的域名必须与客户端请求的域名一致
验证信息是否匹配
浏览器读取证书中相关的明文信息,采用 CA 签名时相同的 Hash 函数来计算并得到信息摘要 A;
利用对应 CA 的公钥解密签名数据,得到信息摘要 B;
对比信息摘要 A 和信息摘要 B,如果一致,则可以确认证书是合法的;
验证证书是否被篡改
数字证书的认证
存在DNS劫持安全问题(服务器端发送给浏览器端的公钥换成数字证书)
黑客可以在用户计算机上安装假数字证书
SSL/TLS 的会话重用
使用轻量级加密算法
服务器配置专门的加密芯片
CDN加速,相当于负载均衡了
HTTP2来多路复用等特性
性能短板
https(解决中间人攻击)
每个域名只使用一个TCP长连接,减少慢启动
多路复用(将请求分成一帧一帧的数据去传输)
头部压缩
TCP 的头部阻塞
和 web socket 协议的区别
Server Push
http2
应用层 HTTP协议
TCP/IP 四层模型
传输层(UDP/TCP)定义了一些传输数据的协议和端口号(www端口 80等)
OSI 七层模型
ARP协议,其实是介于网络层和链路层的协议,是通过 IP 地址查找 MAC 地址的
网络协议
CSP,满足安全地引入第三方资源,防止XSS攻击
CORS,满足跨域请求
postMessage,满足跨文档通信
同源策略(协议、域名、端口都相同)
服务器对输入脚本进行过滤或者转码
充分利用CSP
利用 HttpOnly 属性
XSS 跨站脚本攻击
利用 SameSite 属性
利用 Origin 或者 Referer 属性
CSRF Token
CSRF 跨站资源伪造(不需要将恶意代码注入用户的页面,利用服务器的漏洞和用户的登录状态来实施攻击)
安全
利用 ESP(当前执行状态的指针) 的下移,来销毁栈内存中的数据
栈内存中数据
副垃圾回收器
大部分对象在内存中存在的时间很短,简单来说,就是很多对象一经分配内存,很快就变得不可访问;(新生代)
主垃圾回收器
不死的对象,会活得更久(旧生代)
堆内存中数据(根据代际假说分成两类)
垃圾回收机制
浏览器
栈
队列
删除链表中节点
判断是否是环形链表
链表反转
链表两数相加
删除重复链表
链表
集合
字典
BFS(栈)
DFS(递归)
前序(根-左-右)
中序(左-根-右)
后序(左-右-根)
递归(最为简单),也可以利用 while 循环 + stack 结构来代替递归
树
冒泡排序:双层循环不断前后对比复杂度:O(n^2)
选择排序:双层循环每次找到最小的复杂度:O(n^2)
插入排序:双层循环,从索引1的数字依次向前比较复杂度:O(n^2)
快速排序:找到一个基准数,进行分区操作,再递归依次处理下去复杂度:分区O(n) * 递归O(logN) = O(n * logN)
二分法
排序
分治
动态规划
回溯
3
无重复字符的最长子串
滑动模块
5
最长回文子串
15
三数之和等于0(排序后双指针,考虑重复问题)
双指针
4
寻找两个正序数组的中位数(拆解为两个数组的合并)
20
有效的括号
21
链表合并
19
删除链表的倒数第N个节点(链表反转+删除链表某个节点)
22
括号的生成
BFS、DFS
LeetCode HOT100
算法
前端
0 条评论
回复 删除
下一页