2022金三银四前端面试笔记
2022 金三银四 真可谓 铜三铁四 !伴随着京东、字节、蚂蚁等头部互联网公司员工被大量被优化,我也一把鼻涕一把泪的加入了内卷大军。
下面的主要内容是前端基础知识的梳理(大纲式笔记),具体内容部分有链接可以跳转后深入学习。这部分内容是结合自己的面试经历和市场上大部的反馈整理出的笔记。在此记录一下,方便后续复盘。
特别说明:
如果你正在找工作或者计划跳槽,可以参考单别照抄,强烈建议您手把手整理自己的知识体系,完善自己的思维,形成自己的文档
➕:代表综合自己所有面试被问到的频率
🔥:市场反馈的热度
正文如下
零、面试相关#
- 面试阶段
- 一面
- 二面
- hr 面
- ➕➕➕个人介绍 🔥🔥🔥
- 面试官你好,我叫 xx,19 年毕业,目前有近 3 年的工作经验
- 在技术方面对 react 比较熟悉,也能写点 typescript;
- 在上一家公司主要负责 xx 平台官网的建设重构以及维护,也会进行基础设计的建设和通用打包脚本的编写和维护,也参与了物料平台的的设计以及 c 项目的初始化等工作
- 平时喜欢从共工作中总结问题并得出一些通用的解决方案;常年混迹于 github,参与过大型开源项目并且贡献过 pr
壹、HTML 相关#
- ➕HTML 语义化
- 是什么
- 用合适的标签描述清晰的结构和内容
- 为什么(作用)
- 让开发者和机器更容易理解,便于维护
- 让爬虫更容易爬取,有利于 seo
- 怎么做
- 框架集成(next 等
- 三方库(seo
- 自己怎么写
- lighthouse
- 语义化标签
- header
- footer
- 不用非语义化标签
- div
- span
- sitemap
- 是什么
贰、CSS 相关#
- ➕➕BFC 的形成和作用 🔥🔥🔥
- 是什么
- 块级格式上下文
- 只有块级盒子参与的独立独立渲染区域
- 规定了内部块级盒子如何布局且与区域外部无关
- 触发
- 跟元素(html 元素)
- float
- overflow(不为 visible)
- position(不为 relative 和 static)
- display
- inline-block
- flex
- grid
- table
- 作用
- 修复浮动元素造成的高度塌陷问题
- 防止 margin 重叠
- 实现灵活健壮的自适应布局
- 解析
- 触发 BFC 的条件,创建 BFC
- 在同一个 BFC 中,相邻块级盒子的垂直外边距会合并
- 在 BFC 中,每一个盒子的左外边缘(margin-left)会触碰到包含块的左边缘
- 深入
- 盒模型
- 视觉格式化模型
- 决定盒子的大小、位置以及属性(例如颜色、背景、边框尺寸等等)
- 包含块
- 大部分情况下,包含块是一个由元素最近的祖先块容器的内容区域(content area)确定的矩形区域,
- 包含块本身不是盒子,是一个矩形区域
- 元素的大小,位置,及偏移等布局信息根据包含块的尺寸进行计算
- 正常流
- 正常流是浏览器的默认布局方式
- 在正常流中的盒子,属于 BFC,IFC,或其他格式化上下文之一
- 格式化上下文
- 块级格式化上下文(BFC,block formatting context)
- 内联格式化上下文(IFC,inline formatting context)
- 弹性格式化上下文(FFC,flex formatting context),在 CSS3 中定义
- 栅格格式化上下文(GFC,grid formatting context),在 CSS3 中定义
- 独立格式化上下文
- 一个盒子要么建立一个新的独立格式化上下文,要么延续其包含块的格式化上下文
- 除了特殊说明,建立新的格式化上下文就是在建立一个独立格式化上下文
- 是什么
- 谈谈 CSS 预处理器 🔥🔥
- 是什么?为什么?
- CSS 本身不属于可编程语言,当前端项目逐渐庞大之后 CSS 的维护也愈加困难
- CSS 预处理器所做的本质上是为 CSS 增加一些可编程的特性,通过变量、嵌套、简单的程序逻辑、计算、函数等特性,通过工程化的手段让 CSS 更易维护,提升开发效率
- 那些预处理器?
- PostCSS
- 特点
- 本体功能比较单一
- 把 CSS 解析成 AST,插件化增强功能
- 功能
- Autoprefixer 为 CSS 中的属性添加浏览器特定的前缀
- postcss-preset-env 根据 browserslist 指定的目标浏览器将一些 CSS 的新特性转换为目标浏览器所支持的语法
- cssnano 提供 CSS 压缩功能
- postcss-nested 提供 CSS 嵌套功能
- postcss-px-to-viewport 提供 px 转 vw 功能
- postcss-custom-properties 支持 CSS 的自定义属性
- 优点
- 插件系统完善,扩展性强。
- 配合插件功能齐全。
- 生态优秀。
- 缺点
- 配置相对复杂
- 特点
- Sass、Less
- 特点
- 完全兼容 CSS 语法
- less 浏览器端直接使用。
- 功能
- 变量、嵌套、混合、操作符、自定义函数等可编程能力
- 优点
- 使用广泛。
- 功能支持完善。
- 可编程能力强。
- 缺点
- CSS 的复杂度不可控。
- node-sass 国内安装不易(非 Sass 本身的缺点,dart-sass 可代替)。
- less 不支持自定义函数(可通过 mixins 实现简单逻辑)
- 特点
- Stylus
- 与 less sass 类似
- 最大的特点就是简洁(冒号、分号、逗号和括号都是可选项)
- PostCSS
- 扩展
- CSS Modules
- 特点
- 与预处理器不同,不是可编程化的 CSS
- CSS 文件加入了作用域和模块依赖
- 作用(优点)
- 解决 CSS 全局污染的痛点
- 特点
- CSS-in-JS
- 特点
- 在 JavaScript 里写 CSS 的方式
- 优点
- JS 的优势可实现非常灵活的可扩展的样式
- 特点
- Tailwind 和 Utility-first CSS
- 特点
- 功能类优先(Utility-first CSS)的理念
- 优点
- 不用考虑 class 的命名
- CSS 文件大小增长可控,通过 purge 可生成非常小的 CSS 文件
- 特点
- CSS Modules
- 是什么?为什么?
- ➕水平垂直居中方案 🔥🔥🔥
- flex
- grid
- 相对定位
- transform:translate
- calc
- 绝对定位
- transform:translate
- calc
- margin
- left,right
- auto
- 表格布局
- table-cell
- line-height
- ➕➕移动端自适应的常见手段 🔥🔥🔥
- 痛点(为什么)
- 使不同的终端设备都拥有基本一致的视觉效果和交互体验
- 适配方案
- 视口元信息配置
- 响应式布局
- flex
- grid
- 相对单位
- vw、vh
- rem
- 媒体查询
- 响应式图片
- 安全区域适配
- 痛点(为什么)
- ➕css 清除浮动
- clear:both/left/right
- 触发 bfc
- 让父级元素跟着浮动
- ➕ 旋转盒子
- animation + transform:rotate
- ➕ 单行/单行文本溢出省略
- 单行
- overflow:hidden
- white-space:nowrap
- text-overflow: ellipsis
- 多行
- 伪元素+ 绝对定位
- clamp 属性
- 单行
- ➕➕ 两栏布局左侧自适应、三栏布局中间自适应
- 两栏
- float:left ;margin-left ;BFC
- display:flex;flex:1;
- 三栏
- float:left,right;margin: left,right
- 绝对定位
- float+-margin
- dislplay: table
- flex
- grid
- 两栏
- ➕flex
叁、JavaScript 相关#
-
➕➕➕ES6+新特性 🔥🔥
-
let,const
- 和 var 区别
- 变量提升
- 暂时性死区
- 块级作用域
- 重复声明
- 修改声明的变量
- 和 var 区别
-
数组扩展
- ...
- slice
- splice
-
对象扩展
- ...
-
函数扩展
- 箭头函数
-
set,map
- WeakSet/WeakMap
- 成员只能是引用类型(对象作为键),而不能是其他类型的值
-
场景#
- WeakSet/WeakMap
-
promise
- all
- allSettled()
- race
- ES6 中 Promise 的理解?
-
generator
- 场景
- 原生对象没有遍历接口,通过 Generator 函数为它加上这个接口,就能使用 for...of 进行遍历了
- Generator 是异步解决的一种方案
- 场景
-
proxy
-
moduler
- 为什么
- 代码抽象
- 代码封装
- 代码复用
- 依赖管理
- 为什么
-
decorator
-
-
- 浅拷贝
- Object.asign()
- [...arr]
- arr.slice()
- arr.concat()
- 深拷贝
- _.deepclone
- JSON.stringify()
- undefined
- Symbol
- 函数
- 手写
- 浅拷贝
-
- 是什么
this
的值是在代码运行时计算出来的,它取决于`代码上下文
- 判断
- 默认绑定
- 隐式绑定
- new 绑定
- 显示修改
- call
- apply
- bind
- 箭头函数
- addEventListener 中的 this 是啥?
- element
- 是什么
-
- 是什么
- 执行上下文是一种对 Javascript 代码执行环境的抽象概念,也就是说只要有 Javascript 代码运行,那么它就一定是运行在执行上下文中
- 生命周期
- 创建
- 执行
- 回收
- 是什么
-
- 是什么?
- 函数+变量的总合
- 表现
- 能够在函数定义的作用域外,使用函数定义作用域内的局部变量,并且不会污染全局
- 原理
- 基于词法作用域链和垃圾回收机制,通过维持函数作用域的引用,让函数作用域可以在当前作用域外被访问到
- 应用
- 无论何时何地,如果将函数作为返回值,就会看到闭包在这些函数中的应用
- 在定时器,事件监听器,ajax 请求,跨窗口通信,web workers 或者任何其他的异步/同步任务中,只要使用了回调函数,实际上就是使用闭包
- 是什么?
-
- 原型链继承
- 一个引用类型继承另一个引用类型的属性和方法
- 借用构造函数继承
- 子类型构造函数中调用父类的构造函数,使所有需要继承的属性都定义在实例对象上
- 组合继承(伪经典继承)
- 使用原型链实现对原型属性和方法的继承,借用构造函数实现对实例属性的继承
- 寄生组合式继承
- 借用构造函数来继承属性,使用混合式原型链继承方法
- ES6 中 class 的继承
- 原型链继承
-
- 是什么
- 通过执行自定义构造函数或内置对象构造函数,生成对应的对象实例
- 实现
- 是什么
-
TypeScript 中的 Interface 和 Type Alias🔥🔥🔥
- 区别
- Type 不可在定义后重新添加内容,而 Interface 则总是可以扩展新内容
- 相比 Interface,Type 并没有实际创建一个新的类型,而是创建一个引用某个类型的名字
- Interface 只能操作对象类型,Type 可以操作任意类型
- 区别
-
- 是什么?
- JavaScript 是一种同步的、阻塞的、单线程的语言,一次只能执行一个任务。
- 但浏览器定义了非同步的 Web APIs,将回调函数插入到事件循环,实现异步任务的非阻塞执行
- 方案
- 是什么?
-
➕slice 和 splice 的区别
- array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
-
➕➕for in / for of 区别
-
➕forEach / map 区别
肆、Browser 相关#
-
- 是什么
- 同源策略(same-origin policy)是浏览器的为了请求安全而做的限制,协议(protocol)+主机(host)+端口(port)不一致则为跨域
- 后端不受此限制,可以通过 CORS 等方式解决跨域
- 方案
- CORS (Cross-Origin Resource Sharing)
- 只需要后端支持
- 在响应头中添加 Access-Control-Allow-*
- 反向代理
- 只需要后端支持
- 依赖同源的服务端对请求做一个转发处理,将跨域请求转换成同源请求
- JSONP
- 需要服务端和前端配合实现
- 利用了浏览器加载 JavaScript 资源文件时不受同源策略的限制而实现跨域获取数据
- 非常用方式
- postMessage
- 即在两个 origin 下分别部署一套页面 A 与 B,
- A 页面通过 iframe 加载 B 页面并监听消息,B 页面发送消息
- window.name
- 主要是利用 window.name 页面跳转不改变的特性实现跨域,
- 即 iframe 加载一个跨域页面,设置 window.name,跳转到同域页面,可以通过 $('iframe').contentWindow.name 拿到跨域页面的数据
- document.domain
- 可将相同一级域名下的子域名页面的 document.domain 设置为一级域名实现跨域
- 可将同域不同端口的 document.domain 设置为同域名实现跨域(端口被置为 null)
- postMessage
- 扩展
- LocalStorage / SessionStorage 跨域
- 跨域与监控
- 跨域与图片
- CORS (Cross-Origin Resource Sharing)
- 是什么
-
- 是什么?
- 浏览器渲染大致分为四个阶段,在解析完 HTML 依次进入 layout (重排)和 paint (重绘)。
- 节点或者样式的变更以及对布局信息的访问等,都可能导致重排或者重绘;
- 重排和重绘在主线程中进行,者意味着不合理的重排和重绘会导致页面卡顿等性能问题
- 为什么?
- 不合理的重排和重绘会导致占用浏览器主线程,导致卡顿等性能问题
- 浏览器渲染关键路径
- parse HTML
- dom tree
- cssom tree
- render tree
- lauyout
- 尺寸
- 位置
- paint
- 节点到像素
- 发生在多个图层
- composition
- 合并图层
- 渲染到屏幕
- parse HTML
- 触发
- 节点变更-导致重排
- 盒子尺寸、类型
- 定位方案
- 文档中节点关系
- 外部信息(视口)
- 第一次渲染
- 外观变化-导致重绘
- 样式改变
- 获取布局信息(会及时计算所以会重排)
- 属性
- offset 系列
- client 系列
- scroll 系列
- 方法
- getComputeStyle
- 属性
- 节点变更-导致重排
- 减少(方案)
- 对 DOM 进行批量写入和读取(通过虚拟 DOM 或者 DocumentFragment 实现)
- 避免对样式频繁操作
- 避免频繁读取样式信息,使用变量缓存
- 是什么?
-
-
url 输入
- 合法性校验
-
dns 解析
- 浏览器 DNS 缓存
- 操作系统的 DNS 缓存(hosts)
- 本地域名服务器(递归查询)
- 上级域名服务器(迭代查询)
-
建立 tcp 连接(三次握手)
-
发送 http 请求
- 请求行
- 请求头
- 请求体
-
服务器响应请求
- 响应行
- 响应头
- 响应体
-
浏览器解析页面
- 查看响应头的信息,根据不同的指示做对应处理
- 重定向
- 存储 cookie
- 解压 gzip
- 缓存资源
- 根据不同的资源类型(Content-Type)采用不同的解析方式
- 浏览器渲染关键路径
- parse HTML
- dom tree
- cssom tree
- render tree
- lauyout
- 尺寸
- 位置
- paint
- 节点到像素
- 发生在多个图层
- composition
- 合并图层
- 渲染到屏幕
- parse HTML
- 查看响应头的信息,根据不同的指示做对应处理
-
断开 tcp 连接(四次挥手)
- tab 标签页关闭时
-
-
- 关键路径
- parse HTML
- 构建 dom tree
- Conversion(转换):字节 =》字符
- Tokenizing(分词):, 等标记
- Lexing(语法分析):标记将被转换为对象(包含属性,属性值,文本等)
- DOM construction(DOM 构造):连接对象生成树结构
- 预加载次级资源
- 预加载扫描器(preload scanner)线程并发加载图片、JavaScript、CSS、字体等资源
- 遇到 script 标签时,会暂停 HTML 的解析
- 构建 dom tree
- style 样式计算
- 构建 cssom tree
- 搜集样式,建立索引
- 遍历 DOM 树,通过选择器匹配样式,并设置样式
- 层叠样式,生成最终样式
- CSSOM 和 DOM 是并行构建
- CSSOM 会阻塞 JS 的执行(因为 JS 可能会操作样式信息)
- 但在进入下一阶段之前,必须等待 CSSOM 构建完成(这也是通常所说的 CSSOM 会阻塞渲染)
- 构建 cssom tree
- lauyout
- 合并 layout tree
- 计算可见的节点及其样式
- 从 dom 树 遍历每个可见节点
- 为其找到适配的 CSSOM 规则并应用(包含内容和样式)
- 确切位置和大小
- 根据 CSS 盒模型及视觉格式化模型,计算每个元素的各种生成盒的大小和位置
- 计算块级元素、行内元素、浮动元素、各种定位元素的大小和位置
- 计算文字,滚动区域的大小和位置
- 计算可见的节点及其样式
- 合并 layout tree
- paint
- 将 LayoutObject 树转换成供合成器使用的高效渲染格式
- 节点到像素
- 发生在多个图层
- composition
- 合并图层
- 渲染到屏幕
- parse HTML
- 优化性能
- 保证渲染流程不被阻塞,避免不必要的绘制计算和重排重绘
- (以动画为例)
- 使用合适的网页分层技术:如使用多层 canvas,将动画背景,运动主体,次要物体分层,这样每一帧需要变化的就只是一个或部分合成层,而不是整个页面
- 使用 CSS Transforms 和 Animations:它可以让浏览器仅仅使用合成器来合成所有的层就可以达到动画效果,而不需要重新计算布局,重新绘制图形
- 优化影响渲染的资源
- 关键 CSS 资源放在头部加载。
- JS 通常放在页面底部。
- 为 JS 添加 async 和 defer 属性。
- body 中尽量不要出现 CSS 和 JS。
- 为 img 指定宽高,避免图像加载完成后触发重排。
- 避免使用 table, iframe 等慢元素。原因是 table 会等到它的 dom 树全部生成后再一次性插入页面中;iframe 内资源的下载过程会阻塞父页面静态资源的下载及 css, dom 树的解析
- 用 GPU 硬件加速
- 保证渲染流程不被阻塞,避免不必要的绘制计算和重排重绘
- 关键路径
-
- 是什么?
- 一种内存自动管理机制, 垃圾回收器(Garbage Collector)可以自动回收分配给程序的已经不再使用的内存
- 常见的 GC 算法有引用计数法和标记清除法等
- 内存泄漏
- 应当被回收的对象没有被正常回收
- 方案
- 标记清除
- 引用计数
- 是什么?
-
- 是什么?
- 一种程序结构,消息分发器
- 浏览器主线程是单线程的,为了使定时器,用户脚本等异步操作非阻塞的运行,浏览器通过任务队列来管理异步任务
- 事件调度
- 执行同步代码。
- 执行一个宏任务(执行栈中没有就从任务队列中获取)
- 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
- 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
- 当前宏任务执行完毕,开始检查渲染,然后渲染线程接管进行渲染
- 渲染完毕后,JavaScript 线程继续接管,开始下一个循环
- 宏任务与微任务
- 宏任务主要包含:
- script(整体代码)、
- setTimeout、
- setInterval、
- setImmediate、
- I/O、
- UI 交互事件
- 微任务主要包含:
- Promise、
- MutationObserver
- script(整体代码)、
- 常考例题
- 是什么?
-
- devtools
- Performance
- Memory
- --inspect
- devtools
-
- 是什么?
- 源地址到目标地址的活动
- Web:url 到对应程序的映射
- 实现
- 前后端均可实现
- 前端路由
- hash 路由
- 触发 onhaschange 监听 hash 的变化
- 不会重新刷新页面
- 改变浏览器历史记录
- history 路由(依赖 History API 里的两个方法和一个事件)
- history.pushState
- hisstory.replaceState
- popstate
- hash 路由
- 应用
- 无刷新的单页应用开发模式 SPA
- 优缺点
- hash
- 兼容性最佳
- 无需服务端配置
- 服务端无法获取 hash 部分内容
- 可能和锚点功能冲突
- SEO 不友好
- histroy
- 服务端可获取完整的链接和参数。
- 前端监控友好。
- SEO 相对 Hash 路由友好。
- 兼容性稍弱。
- 需要服务端额外配置(各 path 均指向同一个 HTML)。
- hash
- 是什么?
-
➕ 正则表达式
- 创建
- 字面量
- RegExp 构造函数
- 匹配规则
- 贪婪模式
- 懒惰模式
- 分组
- 匹配方法
- match、matchAll、search、replace、split
- test、exec
- 创建
伍、网络协议#
- ➕前端安全 🔥🔥🔥
- XSS(跨站脚本攻击)
- 是什么
- 将代码注入到其他用户浏览器的攻击方式
- 类型
- 反射型(非持久性)
- 原理:
- 攻击者通过在 URL 插入恶意代码,其他用户访问该恶意链接时,服务端在 URL 取出恶意代码后拼接至 HTML 中返回给用户浏览器
- 要点:
- 通过 URL 插入恶意代码
- 有服务端参与
- 需要用户访问特定链接
- 原理:
- 存储型(持久性)
- 原理:
- 攻击者将注入型脚本提交至被攻击网站数据库中,当其他用户浏览器请求数据时,注入脚本从服务器返回并执行
- 要点:
- 恶意代码存储在目标网站服务器上
- 有服务端参与
- 只要用户访问被注入恶意脚本的页面时,就会被攻击
- 原理:
- DOM 型
- 原理:
- 攻击者通过在 URL 插入恶意代码,客户端脚本取出 URL 中的恶意代码并执行。
- 要点:
- 在客户端发生
- 原理:
- 反射型(非持久性)
- 防范 XSS
- 对于外部传入的内容进行充分转义
- 开启 CSP(Content Security Policy,内容安全策略),规定客户端哪些外部资源可以加载和执行,降低 XSS 风险
- 设置 Cookie httpOnly 属性,禁止 JavaScript 读取 Cookie 防止被窃取
- 是什么
- CSRF(跨站请求伪造)
- 是什么
- 窃用其身份在对应的网站进行操作
- 要点:
- 利用浏览器在发送 HTTP 请求时会自动带上 Cookie 的原理,冒用受害者身份请求
- 攻击一般发生在第三方网站上
- 攻击者只能“冒用”受害者的身份凭证,并不能获取
- 跨站请求有多种方式,常见的有图片 URL、超链接、Form 提交等
- 防范 CSRF
- 使用 CSRF Token 验证用户身份
- 双重 Cookie 验证
- 设置 Cookie 的 SameSite 属性可以用来限制第三方 Cookie 的使用
- 是什么
- 中间人攻击(MITM)
- 是什么
- 攻击者与通讯的两端分别创建独立的联系,在通讯中充当一个中间人角色对数据进行监听、拦截甚至篡改
- 原理
- 拦截
- 解密
- SSL 劫持(伪造证书)
- 中间人攻击防范
- 对于开发者来说:
- 支持 HTTPS
- 对于用户来说:
- 尽可能使用 HTTPS 链接
- 避免连接不知名的 WiFi 热点
- 不忽略不安全的浏览器通知
- 公共网络不进行涉及敏感信息的交互
- 用可信的第三方 CA 厂商,不下载来源不明的证书
- 对于开发者来说:
- 是什么
- XSS(跨站脚本攻击)
- ➕➕HTTP 缓存机制 🔥🔥🔥
- 强缓存
- 是什么
- 可以通过 Expires / Cache-Control 控制
- 命中强缓存时不会发起网络请求,资源直接从本地获取,浏览器显示状态码 200 from cache
- expires
- HTTP/1.0 产物。
- 优先级低于 Cache-control: max-age。
- 缺点:使用本地时间判断是否过期,而本地时间是可修改的且并非一定准确的
- cache-control
- HTTP/1.1 产物
- 优先级高于 Expires
- 正确区分 no-cache / no-store 的作用
- no-cache 强制客户端向服务器发起请求(禁用强缓存,可用协商缓存)。
- no-store 禁止一切缓存,包含协商缓存也不可用。
- 是什么
- 协商缓存
- 是什么
- 可以通过 Last-Modified / If-Modified-Since 和 Etag / If-None-Match 控制,
- 开启协商缓存时向服务器发送的请求会带上缓存标识,若命中协商缓存,服务器返回 304 Not Modified 表示浏览器可以使用本地缓存文件,否则返回 200 OK 正常返回数据
- Last-Modified / If-Modified-Since
- 通过资源的最后修改时间来验证缓存。
- 优先级低于 ETag / If-None-Match。
- 缺点:只能精确到秒,若 1s 内多次修改资源 Last-Modified 不会变化
- ETag / If-None-Match
- 通过唯一标识来验证缓存。
- 优先级高于 Last-Modified / If-Modified-Since。
- 是什么
- 优缺点
- 优点
- 节省了不必要的数据传输,节省带宽。
- 减少服务端的负担,提高网站性能。
- 降低网络延迟,加快页面响应速度,增强用户体验。
- 缺点
- 不恰当的缓存设置可能会导致资源更新不及时,导致用户获取信息滞后。
- 优点
- 强缓存
- ➕HTTP/2 和 HTTP/1.1 的对比 🔥🔥🔥
- HTTP/1.1 相较 HTTP/1.0 的改进和优化:
- 持久连接
- Connection: keep-alive
- HTTP 管道化
- 多个 HTTP 同时请求,响应必须按照请求发出的顺序依次返回
- 问题
- 对头阻塞
- 服务端缓存前序请求
- 分块编码传输
- Transfer-Encoding: chunked
- 新增 Host 头处理
- http/1.0 每台服务器都绑定一个唯一的 IP 地址(因此一台服务器也无法搭建多个 Web 站点)
- 断点续传、并行下载
- 请求头字段 Range
- 响应头字段 Content-Range
- 持久连接
- HTTP/1.1 的缺点:
- 队头阻塞(Head-of-line blocking)
- 头部冗余
- HTTP 请求每次都会带上请求头,若此时 cookie 也携带大量数据
- TCP 连接数限制
- HTTP/2 的优点:
- 二进制分帧层
- 在 HTTP/1.x 中传输数据使用的是纯文本形式的报文,需要不断地读入字节直到遇到分隔符为
- HTTP/2 则是采用二进制编码,将请求和响应数据分割为一个或多个的体积小的帧
- 多路复用
- 并行地处理多个请求和响应
- Header 压缩
- 服务端推送
- 二进制分帧层
- HTTP/1.1 相较 HTTP/1.0 的改进和优化:
- get 和 post 的区别
- 从缓存的角度,GET 请求会被浏览器主动缓存下来,留下历史记录,而 POST 默认不会。
- 从编码的角度,GET 只能进行 URL 编码,只能接收 ASCII 字符,而 POST 没有限制。
- 从参数的角度,GET 一般放在 URL 中,因此不安全,POST 放在请求体中,更适合传输敏感信息。
- 从幂等性的角度,GET 是幂等的,而 POST 不是。(幂等表示执行相同的操作,结果也是相同的)
- 从 TCP 的角度,GET 请求会把请求报文一次性发出去,而 POST 会分为两个 TCP 数据包,首先发 header 部分,如果服务器响应 100(continue), 然后发 body 部分。(火狐浏览器除外,它的 POST 请求只发一个 TCP 包)
- ➕https
陆、前端工程化#
-
- 是什么?
- webpack 是一种模块打包工具,可以将各类资源(js,css,图片,字体等-一切皆可打包)转译组合为 JS 格式 的 bundle 文件
- 为什么?
- 提高效率
- 基本概念
- Entry:入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入
- Module:模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块
- Chunk:代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割
- Loader:模块转换器,用于把模块原内容按照需求转换成新内容
- Plugin:扩展插件,在 Webpack 构建流程中的特定时机会广播出对应的事件,插件可以监听这些事件的发生,在特定时机做对应的事情
- 核心任务
- 完成内容转化和资源合并,可以分为以下三大阶段
- 初始化阶段
- 读取与合并配置参数
- 实例化 Compiler
- 加载 Plugin
- 编译阶段
- 从 Entry 发出,针对每个 Module 串行调用对应的 Loader 去翻译文件内容
- 再找到该 Module 依赖的 Module,递归地进行编译处理
- 输出阶段
- 对编译后的 Module 组合成 Chunk
- 把 Chunk 转换成文件,输出到文件系统
- 是什么?
-
- 是什么?
- 为什么?
- 模块化可以解决代码之间的变量、函数、对象等命名的冲突/污染问题,良好的模块化设计可以降低代码之间的耦合关系,提高代码的可维护性、可扩展性以及复用性
- 模块化规范的作用是为了规范 JavaScript 模块的定义和加载机制,以统一的方式导出和加载模块,降低学习使用成本,提高开发效率
-
优缺点#
-
- 是什么?
- Babel 是 JavaScript 编译器
- Babel 内部原理是将 JS 代码转换为 AST,对 AST 应用各种插件进行处理,最终输出编译后的 JS 代码
- Babel 编译流程
- 解析阶段:Babel 默认使用 @babel/parser 将代码转换为 AST。解析一般分为两个阶段:词法分析和语法分析
- 词法分析:对输入的字符序列做标记化(tokenization)操作。
- 语法分析:处理标记与标记之间的关系,最终形成一颗完整的 AST 结构。
- 转换阶段:
- Babel 使用 @babel/traverse 提供的方法对 AST 进行深度优先遍历,调用插件对关注节点的处理函数,按需对 AST 节点进行增删改操作
- 生成阶段:
- Babel 默认使用 @babel/generator 将上一阶段处理后的 AST 转换为代码字符串
- 解析阶段:Babel 默认使用 @babel/parser 将代码转换为 AST。解析一般分为两个阶段:词法分析和语法分析
- 是什么?
-
- 是什么?
- loader 本质上是一个函数,该函数对接收到的内容进行转换,返回转换后的结果
- webpack 本身只能处理 JavaScript 和 JSON 文件,而 loader 为 webpack 添加了处理其他类型文件的能力。loader 将其他类型的文件转换成有效的 webpack modules(如 ESmodule、CommonJS、AMD),webpack 能消费这些模块,并将其添加到依赖关系图中
- 常见的 loader 有:
- raw-loader:加载文件原始内容。
- file-loader:将引用文件输出到目标文件夹中,在代码中通过相对路径引用输出的文件。
- url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式将文件内容注入到代码中。
- babel-loader:将 ES 较新的语法转换为浏览器可以兼容的语法。
- style-loader:将 CSS 代码注入到 JavaScript 中,通过 DOM 操作加载 CSS。
- css-loader:加载 CSS,支持模块化、压缩、文件导入等特性。
- 是什么?
-
➕➕➕ 提高 webpack 的构建速度
- 缩小查找范围
- 指定 loader 的 include,exlude,正则
- 指定 node_modules 为决定路径,优化 resolve.modules
- 指定文件后缀,合理使用 resolve.extensions
- 优化 resolve.alias
- 使用缓存,cache-loader
- 启用多线程
- 合理使用 soucemap
- 开发模式上 vite
- 缩小查找范围
-
➕ 为什么用 webpack 用 gulp 不行么
- gulp 强调的是一个前端构建工作流(配置一系列的 task(压缩,编译,复制,启动)并发或者按照一定顺序执行)
- webpack 侧重打包(模块化)可以把开发中所有的资源(js,css,图片,字体)都看作模块,通过 loader 和 plugin 进行处理,最终生成 bundle
- gulp 与 webpack 的区别 - 海角在眼前 - 博客园 (cnblogs.com)
-
➕ 为什么使用 monorepo?
- mutirepo 的痛点
- 代码难以复用
- 优点
- 统一的工作流
- 代码复用
- 工程管理
- mutirepo 的痛点
柒、框架和类库#
- ➕➕➕React Fiber 的作用和原理 🔥🔥🔥
- 是什么?
- 是 React 16 中采用的新协调(reconciliation)引擎,主要目标是支持虚拟 DOM 的渐进式渲染
- 对比
- Stack Reconciler 替换为 Fiber Reconciler
- 任务的分片
- 任务划分优先级
- 任务可挂起、恢复、终止等操作
- Stack Reconciler 替换为 Fiber Reconciler
- Fiber 的主要工作流程:
- ReactDOM.render() 引导 React 启动或调用 setState() 的时候开始创建或更新 Fiber 树。
- 从根节点开始遍历 Fiber Node Tree, 并且构建 workInProgress Tree(reconciliation 阶段)。
- 本阶段可以暂停、终止、和重启,会导致 react 相关生命周期重复执行。
- React 会生成两棵树,一棵是代表当前状态的 current tree,一棵是待更新的 workInProgress tree。
- 遍历 current tree,重用或更新 Fiber Node 到 workInProgress tree,workInProgress tree 完成后会替换 current tree。
- 每更新一个节点,同时生成该节点对应的 Effect List。
- 为每个节点创建更新任务。
- 将创建的更新任务加入任务队列,等待调度。
- 调度由 scheduler 模块完成,其核心职责是执行回调。
- scheduler 模块实现了跨平台兼容的 requestIdleCallback。
- 每处理完一个 Fiber Node 的更新,可以中断、挂起,或恢复。
- 根据 Effect List 更新 DOM (commit 阶段)。(已经弃用 effectList)
- React 会遍历 Effect List 将所有变更一次性更新到 DOM 上。
- 这一阶段的工作会导致用户可见的变化。因此该过程不可中断,必须一直执行直到更新完成
- 是什么?
- HOC vs Render Props vs Hooks🔥🔥🔥
- React Hooks 实现原理 🔥🔥🔥
- 原理?
- Hooks 主要是利用闭包来保存状态,使用链表保存一系列 Hooks,将链表中的第一个 Hook 与 Fiber 关联。
- 在 Fiber 树更新时,就能从 Hooks 中计算出最终输出的状态和执行相关的副作用。
- 实现
- 原理?
- ➕➕➕React 事件机制原理 🔥🔥🔥
- 原理
- 两个阶段:
- 初始化渲染时在 root 节点上注册原生事件的回调;
- 原生事件触发时模拟捕获目标和冒泡阶段派发合成事件
- 两个阶段:
- 优点
- 通过这种机制,冒泡的原生事件类型最多在 root 节点上注册一次,节省内存开销。
- 且 React 为不同类型的事件定义了不同的处理优先级,从而让用户代码及时响应高优先级的用户交互,提升用户体验。
- 处理
- React 的事件机制中依赖合成事件这个核心概念。
- 合成事件在符合 W3C 规范定义的前提下,抹平浏览器之间的差异化表现。
- 并且简化事件逻辑,对关联事件进行合成。
- 如每当表单类型组件的值发生改变时,都会触发 onChange 事件,而 onChange 事件由 change、click、input、keydown、keyup 等原生事件组成。
- 流程
- 原生事件触发后,进入 dispatchEvent 回调方法;
- attemptToDispatchEvent 方法根据该原生事件查找到当前原生 Dom 节点和映射的 Fiber 节点;
- 事件和 Fiber 等信息被派发给插件系统进行处理,插件系统调用各插件暴露的 extractEvents 方法;
- accumulateSinglePhaseListeners 方法向上收集 Fiber 树上监听相关事件的其他回调函数,构造合成事件并加入到派发队列 dispatchQueue 中;
- 调用 processDispatchQueue 方法,基于捕获或冒泡阶段的标识,按倒序或顺序执行 dispatchQueue 中的方法;
- 原理
- 常见框架的 Diff 算法 🔥🔥🔥
- mvc 和 mvvm 的区别
- 单页应用如何在浏览器中实现的?单页应用的优缺点
- ➕➕ 高阶组件
捌、React 相关#
- ➕➕➕01 你真的了解 React 么?
- 是什么?(一句话概括)(干嘛的,用途)
- (渐进式)UI 框架
- 通过组件化的方式解决 UI 复用的问题
- 本质是一个组件化的 UI 框架
- 设计思路(特点)
- 声明式
- 声明式的有点在于直观和组合
- 组件化
- 组件化的优点在于便于组件的拆分和组合,更容易做到低耦合和高内聚
- 通用性
- 通用性的优点在于一次学习,多处使用
- 声明式
- 优缺点
- 优点
- 适用范围广,web,native 等
- 缺点
- 不是大而全的框架,生态需要社区维护
- 优点
- 和 vue 的对比!!
- 注意引导
- 优化
- 虚拟 dom
- 自己的项目
- 工程架构和设计模式等
- 是什么?(一句话概括)(干嘛的,用途)
- 02 为什么要用 jsx?
- (潜台词:为什么不用 a,b,b)
- 一句话解释
- JavaScript 的语法扩展,类似于 xml 语法
- 核心概念
- 不强制使用,React.createElement()的语法糖
- 方案对比
- 模板
- 弱关注点分离
- 引入了概念多
- 模板字符串
- 结构描述复杂
- 语法提示差
- 模板
- ➕➕03 声明周期中的坑?
- (潜台词:为什么会有坑)
- 恰当的时机做恰当的事情
- 周期梳理(类组件)
- 挂在阶段
- constructor
- 类构造函数初始化 state 和绑定函数
- 类属性流行后去除了 constructor
- 不推荐做初始化以外的逻辑
- 不属于 react 的生命周期,只是类构造函数的初始化函数
- 更简洁
- getDerivedStateFromProps
- 在 props 变化时,更新 state
- 触发时机(并非 props 变化时执行)
- props 传入时
- state 变化时
- foreUpdate 调用时
- 反模式
- 复制 props 到 state
- props 变化后修改 state
- UNSAGE_componentWilMount
- 异步渲染机制下,调用多次
- 例如同构场景下,客服端和服务端各执行一次
- render
- 执行渲染
- 纯函数
- 不要绑定事件
- 不要嗲用 setsate
- componentDidMount
- 发起网络请求
- constructor
- 更新阶段
- UNSAFE_componentWillReceiveProps
- 被替代
- getDeriveStateFromProps
- 同挂在
- shouldComponentUpdate
- 是否需要触发新的渲染
- 渲染触发的最后关卡,性能优化
- PureComponent 的实现
- UNSAGE_conponentWillUpdate
- 被废弃
- 异步更新出现暂停更新的情况
- render
- 同挂载
- getSnapshotBeforeUpdate
- 配合新的异步渲染机制
- 不可使用 setState
- componentDidUpdate
- getSnapshotBeforeUpdate 作为第三个参数使用
- UNSAFE_componentWillReceiveProps
- 卸载阶段
- conponentWillUnmount
- 解除事件绑定
- 取消定时器
- conponentWillUnmount
- 挂在阶段
- 职责梳理
- 重新渲染
- 函数组件
- 函数组件任何时候都会重新渲染
- React.memo()复用上次的渲染结果
- 类组件
- state 变化时
- props 传入时
- PureComponet
- 函数组件
- 错误处理
- 页面白屏
- componentDidCatch 捕获错位
- 错误边界
- 重新渲染
- 追问
- 请求应该放在那里
- (潜台词:为什么会有坑)
- ➕➕➕04 类组件和函数组件的区别?
- 共同点
- 使用方式一致
- 表达效果一致(性能,UI)
- 不同点
- 心智模型
- OOP
- FP
- 使用场景
- 生命周期
- 设计模式:继承
- 性能优化
- shouldComponentUpdate
- React.memo
- Hooks
- 淡出生命周期,取代类
- 组合优于继承
- 简单
- 易复用
- 心智模型
- 共同点
- ➕05 如何设计 React 组件?
- (背景:如何将组件更好的组合 --- 缺乏一种设计模式)
- 如何组合
- 不同场景吗,组合方式是不一样的
- 设计模式(经典分类)
- 无状态组件(展示组件):只做展示,通用行强,复用性好
- (均是关注点分离的应用)
- 代理组件
- 内聚 props ,封装分层
- 样式组件
- 内聚样式
- 布局组件
- 内聚布局
- 性能优化
- 有状态组件(灵巧组件):处理业务逻辑和状态(组合组件),注重业务本身
- 容器组件
- 拉取数据
- 组合组件
- (关注点分离)
- 高阶组件
- (装饰器写法 - 装饰器模式)
- 抽取公共逻辑
- 登录态校验
- 页面埋点
- 链式调用
- 渲染劫持
- 缺陷
- 丢失静态函数
- refs 属性不能透传
- React.forwordRef
- 容器组件
- 无状态组件(展示组件):只做展示,通用行强,复用性好
- 工程化实践
- 目录结构划分
- 引入工程管理
- (背景:如何将组件更好的组合 --- 缺乏一种设计模式)
- ➕06 setState 是同步更新还是异步更新?
- (不同场景下不同)
- 控制点
- 非真异步
- isBatchUpdate => lanes
- setState 先存入 state 队列
- isBatchUpdte == true 执行异步操作
- isBatchUpate == false 执行同步操作
- 异步场景
- React 生命周期函数中
- React 合成事件中
- 同步场景
- 原生事件
- addEventListener
- setTimeout
- setInterval
- 原生事件
- 原因
- 保持内部一致性,props
- 并发更新,提升性能
- ➕➕07 组件间如何通信?
- (组件树的层级关系,一层,多层)
- 一层
- 父与子
- props 透传(经典设计)
- 场景
- 初始化默认值
- 无状态组件(展示组件)
- 子与父
- 回调函数
- 场景
- 函数作为值传递给子组件
- renderProps():react-router v5
- 父组件专注于渲染结果
- 子组件专注于渲染逻辑
- 实例函数
- 场景
- React Ref 获取子组件的实例
- 兄弟组件
- 共同的父节点进行中转
- 场景
- 容器组件中协调各组件
- 父与子
- 多层
- 嵌套层次太深,无直接联系
- 方案
- context
- 场景
- 国际化
- 场景
- 全局变量
- 临时存储值
- 全局事件
- document 的自定义事件,放在 componetDidMount 中
- 时序依赖
- 状态管理框架
- 成本高
- context
- ➕➕08 列举 React 状态管理库?
- (背景:横跨多个层级共享状态)
- (context 的缺点:难以追溯数据源,提升耦合度,难以复用和测试)
- flux
- redux
- 三大原则(深受函数式编程的影响)
- 单一数据源:应用的数据源存储在一颗 object tree 中,并且只存在唯一一个 store
- 纯函数 reducer:描述 action 如何改变状态树
- state 只读:改变 state 的唯一办法就是触发 action
- 导致
- 所有事件都收拢 action 去触发
- 所有 UI 状态都交给 store 去管理
- 所有的业务逻辑都交给 reducer 去处理
- 三大原则实现了时间回溯功能()
- 副作用
- action ,refucer 都是纯函数,store 只是一个 state 状态树,都不能完成副作用的操作
- 方案
- 在 dispatch 的时候添加中间件,拦截分发的 action 添加额外的复杂行为(副作用等)
- redux-thunk
- redux-sage
- redux-promise
- 在 reducer 中直接处理副作用
- redux-loop
- 大而全的方案
- rematch
- dva
- 在 dispatch 的时候添加中间件,拦截分发的 action 添加额外的复杂行为(副作用等)
- 优点
- 可预测,易测试
- 代码结构严谨,易维护
- 生态丰富
- 三大原则(深受函数式编程的影响)
- mobx
- 监听数据属性的变化,直接在数据上更改来触发 UI 渲染
- mobx5 实现监听的方式采用 Object.defineProperty
- mobx5 之后采用 Proxy
- 追问
- 实现 redux
- 实现 redux-thunk
- 09 Virtual DOM 的工作原理是什么?
- 是什么?(干嘛的,用途)
- 虚拟 dom 是对真实 dom 的高度抽象
- 设计初期为避免大量的 DOM 操作和降低代码整体的风险而引入
- 设计思路(实现)
- render 函数中的 jsx 会被编译为 React.createElement
- React.createElement 返回一个 Plain Object 包含 type tage props chrend 等属性
- Plain Objec 通过属性结构构成一颗虚拟 dom
- 当状态变化时,将前后虚拟 dom 进行对比(diff 算法),生成的结果为 patch
- 渲染 path 完成对真实 dom 的操作
- 优缺点
- 优点
- 改善大规模 DOM 操作的性能
- 规避 xss 风险
- 低成本跨平台开发
- 缺点
- 内存占有高
- 高性能场景难以优化(google earth)
- 优点
- 是什么?(干嘛的,用途)
- 10 React diff 算法有何不同?
- 是什么?(干嘛的,用途)
- 通过对比新旧两颗虚拟 DOM 的变更差异,将更新补丁作用于真实 dom;
- 以最小成本更新视图
- 过程:触发更新 =》生成补丁 =》 应用补丁
- 设计思路(实现)
- 更新时机
- state 变化
- 遍历算法(深度优先)
- 优化策略(分治)
- 树对比
- 只对同层对比
- 组件对比
- 同一类型则进行树对比,不是则直接放入补丁中
- 元素对比
- 同层级元素,通过 key 标记操作生成补丁
- 树对比
- fiber 架构
- 节点和树采用了 fiberNode 和 fiberTree 重构
- fiberNode 使用了双链表
- 跟新过程由 current 和 workProgress 两颗树完成双缓存
- 对比
- preact
- 整体设计相似
- 没有 fiber
- 底层采用真实 dom 对比
- vue
- 整体设计相似
- 没有 fiber
- preact
- 更新时机
- 优缺点
- 可中断更新
- 时间切片
- 追问:根据 diff 如何优化代码
- 避免跨层级节点移动
- 尽量减少组件层级深度
- 设置唯一 key 优化
- 设置 shouldComponentUpdate 或者 React.PureComponet 减少 diff 次数
- 是什么?(干嘛的,用途)
- ➕➕➕11 如何解释 React 的渲染流程?
- (渲染过程大致相同,但协调不同,以 v16 为界 分为 stack reconciler 和 fiber reconciler)
- 15.x
- 核心:
- stack reconciler 调度方式
- 调度
- 递归
- 阶段
- 挂载
- ReactMount 模块完成
- 更新
- ReactUpdate 模块完成
- 卸载
- 挂载
- 事务(基本处理单位)
- 优点
- 原子性(不可再分)
- 隔离性
- 一致性
- 作用
- 链接 react 和虚拟 dom 处理挂载、更新、和卸载等逻辑
- 优点
- 核心:
- 16.x
- 核心:
- fiber reconciler 调度方式
- 调度
- 协作式多任务模式
- requestIdleCallback
- 优先级策略
- 标记 tag
- 协作式多任务模式
- 阶段
- render
- fiber
- 基于 React Element 的二次封装
- 提供父子兄节点的引用=》双向链表
- 可终端,可停止,无副作用
- work
- requestIdleCallback
- 优先级
- workInProgress
- 双缓存树
- fiber
- commit
- 更新 dom 执行副作用
- 同步更新(不可中断)
- render
- 优势
- 提高 react 在动画画布以及手势下的性能表现
- 核心:
- 12 React 渲染异常会造成什么样的结果?
- 是什么?
- 现象
- 页面白屏
- 原理
- 渲染层,空安全
- 现象
- 怎么解决
- 工程化:
- 通用方案
- 预防
- 引入外部函数
- idx
- lodash.get
- bable 插件
- 可选链操作符
- 使用 typescript
- 3.7 以上使用可选链操作符
- 引入外部函数
- 兜底
- 高阶函数
- npm 包
- 预防
- 量化结果
- 覆盖率
- 团队项目 100%
- 统计数
- 线上报警
- 覆盖率
- 通用方案
- 工程化:
- 是什么?
- ➕13 如何分析和调优性能瓶颈?
- 建立衡量指标
- 指标
- FCP
- TTI
- Page Load
- FPS
- 静态资源及 API 请求成功率
- 采集
- lightihouse
- 指标
- 确认优化原因
- 业务场景划分
- 2C
- 管理后台
- ,,,
- 以用户比例划分
- tp50
- tp99
- 业务场景划分
- 实施方案过程
- Loading 图标
- 骨架屏
- 异步加载
- 懒加载
- CDN
- Https
- React
- 长列表
- 重渲染
- 计算效果收益
- 数据
- 技术服务于业务
- 业务指标指导优化
- 效果
- tp50
- tp99
- 数据
- 建立衡量指标
- ➕14 如何避免重复渲染?
- 优化时机
- 业务标准
- 数据支撑
- 定位方式
- 复现
- 工具
- Preformance
- React Profiler
- 常见的坑
- 参数动态变化,使 PureComponent 和 Reat.memo 破防
- jsx 属性使用箭头函数
- 每次都产生新的对象
- 参数动态变化,使 PureComponent 和 Reat.memo 破防
- 处理方案
- 缓存
- reselect 避免产生新的对象
- 不可变数据
- ImmutableJS
- immerjs
- 手动控制
- shuldComponetUpdate
- 缓存
- 优化时机
- 15 如何提升 React 代码的可维护性?
- (潜台词,项目的可维护性)
- 角度
- 软件工程(工程化)
- 维度
- 可分析性
- 目标
- 快速定位线上问题
- 预防
- 人工 code review
- lint 工具校验
- 兜底
- souremap 定位
- 目标
- 可改变性
- 目标
- 易于扩展,易于迭代
- 设计模式
- 组件的设计模式
- 架构设计
- 状态管理框架
- 目标
- 稳定性
- 目标
- 避免修改代码引起线上不必要问题
- 措施
- 核心业务单元测试
- 目标
- 易测试性
- 目标
- 易于发现代码潜在的问题
- 架构划分
- 纯函数
- 目标
- 可维护性
- 遵守约定,提升代码的可读性
- 减少人为因素,加强工具干涉
- eslint
- stylelint
- commitlint
- editorconfig
- prettier
- 可分析性
- ➕➕16 React Hooks 使用限制有哪些?
- 是什么?
- 列举限制
- 不要再循环,条件,嵌套函数中调用 Hook
- 在 React 函数组件中使用 Hook
- 列举限制
- 为什么?
- 设计初衷
- 改进 React 组件开发模式
- 问题领域
- 组件难以复用状态逻辑
- (常见解决方案)
- 高阶函数
- render props
- 状态管理框架
- 复杂的组件难以理解
- 生命周期函数与业务逻辑耦合,导致组件关联部分难以差分
- 人和机器都容易混淆类
- this 问题
- 值捕获问题
- 类属性草案
- 编译优化
- this 问题
- 组件难以复用状态逻辑
- 方案原理
- not magic just array
- 设计初衷
- 怎么做?
- 如何规避
- Eslint
- 如何规避
- 是什么?
- ➕17 useEffect 和 useLayoutEffect 的区别在那里?
- 共同点
- 使用方式
- 函数签名一致
- 底层都是调用 mountEffectImpl
- 函数签名一致
- 运用效果
- 处理副作用
- 使用方式
- 不同点
- 使用场景
- Effect:绝大多数场景
- LayoutEffect:处理 dom 操作,调整样式,避免页面闪烁
- 独有能力
- Effect:异步处理副作用
- LayoutEffect:同步处理副作用
- 设计原理
- Effect:异步调用
- LayoutEffect: 同步调用
- 未来趋势
- 暂无变化
- 使用场景
- 共同点
- ➕➕➕18 谈谈 React Hooks 的设计模式?
- 认知基础
- 抛弃生命周期,向 effects 思考
- 实践心得(规范推广)
- React.memo 被 React.useMemo 替代
- React.memo 不能控制组件内部共享状态的变化
- 常量 和 函数声明
- 函数组件中每次渲染都会重新声明常量和创建函数(无意义的操作)
- useCallback
- useEffect 的第二个参数
- 不要使用引用类型的数据,推荐使用值类型的数据
- JSON.stringify
- 不要使用引用类型的数据,推荐使用值类型的数据
- React.memo 被 React.useMemo 替代
- 外观模式
- 将业务逻辑封装到各自自定义的 hook 中
- 入用户信息操作:获取用户,增加用户,删除用户等
- 组件内部是抽空的,不放具体的业务逻辑,只去带有 hook 暴露的接口
- 有利于测试关键路劲下的业务逻辑
- 将业务逻辑封装到各自自定义的 hook 中
- 认知基础
- 19 React Router 的实现原理和工作方式是什么?
- 实现原理
- 外部:基础原理
- Hash
- Path
- html5 histroy api
- pushState
- replaceState
- historyApiCallback
- html5 histroy api
- 内部:实践方案
- history 库
- 跨平台兼容
- 内存路由
- react-router-native
- 浏览器路由
- react-router-dom
- history 库
- 外部:基础原理
- 工作方式
- 整体:设计模式
- Monorepo
- Context
- 局部:关键模块
- Context 容器
- Router
- MemoryRouter
- 直接消费者,匹配路由
- Route
- Redirect
- Switch
- 。。。
- 与平台关联的功能组件
- Link
- NavLink
- DeepLinking
- Context 容器
- 整体:设计模式
- 实现原理
- 20 React 中常用库有哪些?
- (从开发流程切入)
- 初始化
- create-react-app
- 创建工程
- react-app-rewired 配置
- vite
- dva
- 一站式方案
- umi
- 一站式方案
- create-react-libray
- 创建库
- storybook
- 维护大规模组件
- create-react-app
- 开发
- 路由
- react-router
- 样式
- css module
- css-loader
- css-in-js
- emotion
- styled-component
- css module
- 组件库
- antd
- 功能组件
- 拖拽
- reacnt-dnd
- react-draggable
- 预览 pdf
- react-pdf-view
- 视频播放
- video-react
- 长列表
- react-window
- react-virtualized
- 拖拽
- 状态管理
- redux
- mobx
- 路由
- 构建
- webpack
- rullup
- esbuild
- 检查
- 代码规范检查
- eslint
- 测试
- jest
- enzme
- react-testing-library
- react-hooks-testing-library
- 代码规范检查
- 发布
- s3-pluging-webpack
- ➕ 21 useEffect / useMemo 的区别?
玖、综合场景#
- 多图站点性能优化 🔥🔥🔥
- 图片优化
- 合适的图片格式
- 压缩和缩放图片
- 网络传输优化
- 开启 http/2
- 使用精灵图 / 雪碧图,减少 HTTP 请求数。
- 10kb 大小以内的图片资源使用 base64 编码,减少 HTTP 请求数。
- 通过使用多个域名,开启多个 TCP 连接,突破浏览器同源最大并发连接数的限制。
- 使用 cdn
- 开启 http/2
- 图片加载策略优化
- 懒加载
- 懒加载的策略是推迟加载离屏图片资源,从而减少资源请求数。实现懒加载的主流方案有:
- 使用 img 标签的 loading 属性。
- 使用 Intersection Observer API。
- 使用 scroll、resize 和 orientationchange 事件
- 懒加载的策略是推迟加载离屏图片资源,从而减少资源请求数。实现懒加载的主流方案有:
- 预加载
- 懒加载
- 图片优化
- ➕➕如何减少白屏的时间 🔥🔥🔥
- 分析页面打开过程以及可优化的方向:
- 前置条件
- 性能监控指标
- DNS 解析
- 预解析
- 域名收敛
- TCP 连接
- 预连接
- 请求优化
- HTTP/2
- 页面解析优化
- 服务端渲染
- 预渲染
- 资源加载和页面渲染
- 骨架屏
- 静态资源优化
- 减小资源大小
- Gzip 压缩文件
- JS 文件拆分,动态加载
- 加快资源加载速度
- CDN(Content Delivery Network)
- HTTP/2
- 减小资源大小
- 资源预加载
- prefetch
- preload
- quicklink
- 接口请求优化
- 接口合并
- 前置条件
- 分析页面打开过程以及可优化的方向:
- 如何判断一个元素是否在可视区域中?🔥🔥
- 大文件上传如何做断点续传?🔥
- ➕ 注册功能前端到后端数据库这一套流程 🔥🔥🔥
- ➕npm 包发版
- major.minor.patch
- ^:匹配最近的 minor
- ~:匹配最近的 patch
- *:最新的版本
- major.minor.patch
- ➕ 长列表渲染
- ➕➕➕ 组件库的设计全量导入和按需引入的实现
- ➕ 轮播的实现
拾、数据结构和算法#
- ➕➕➕ 手撕 code
- ➕leetcode
佰、设计模式#
- ➕➕ 为什么要用工厂方法?
- 解耦(关注点分离)
- 不关心如何实例化对象
- 只关心如何使用
- 封装
- 不知道具体内部实例细节
- 解耦(关注点分离)
- ➕ 发布订阅
- 单例模式
- ➕➕➕ 装饰器模式
- 代理模式
仟、技术之外#
- ➕➕➕ 职业规划
- ➕ 怎么评价你
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix