# 无感刷新
无感刷新 token 而不是将 token 过期时间设置很大主要是为了安全性和灵活性,如果 token 泄漏,定时更换 token 可以起到一定的安全性保护
无感刷新:后端维护一个 token 和 RefreshToken 两个令牌,放到响应头中进行返回,使用 token 进行正常的请求验证,当 token 失效时,就去验证 refreshToken 是否有效,如果 refreshToken 有效,就生成新的 token 替换掉旧的 token 并返回。
# 大文件上传
专业术语: 断点续传、断开重连重传、切片上传。
# 方案
- 首先前端将数据进行切片,根据 size 切片为一个个 chunk。
- 接着将切片传递给后端,此时要设置请求头 Content-Type 和 Content-Range, 服务端此时返回的状态码也要对应到 206。
- 传入的切片要标识 id 以便知道 chunk 的顺序。
- 后端将 chunk 进行组合切片。
# 优化
- 主进程将数据进行分片时可以会卡顿,这时使用 web-worker 中进行切片,处理完之后再交给主进程
- 为了防止传到一半用户关闭网页,可以将剩下的 chunks 存到 indexedDB 中,下次进入根据具体业务逻辑进行上传
- 使用 websocket 进行实时通信,和请求序列的控制 wss
# 请求接口大规模并发
# 背景
通常数据采集平台和低代码编辑平台都有大量请求需要相对稳定的发送到后端
使用滑动窗口算法,专门用于控制流量的
# 方案
- 并发请求队列
- 节流防抖
- 分页加载、滚动加载
- 合并相同请求
# IE 适配
适配 IE 浏览器
- IE 浏览器支持识别
IE条件注释
<!--[if IE 8]> | |
<style type="text/css"> | |
/* IE 8 特定的样式 */ | |
</style> | |
<![endif]--> |
- 使用 navigator.userAgent 识别是 IE 浏览器的话就去请求 IE 浏览器的 css 文件
# 移动端适配
# 背景
项目需要支持 PC 端、移动端
# 方案
- 根据媒体查询为不同尺寸设置 css 样式
- 设置一套响应式的 css 布局方案,百分比 + flex+rem 等
- 根据端来开发不同页面
- 根据不同端加载不同 css 文件
- 图片响应式使用 picture 标签中的 media 属性
# 修改第三方 npm 包
- fork 包源码,修改后发布到 npm 私服,但是维护的话需要自己维护
- 修改 node_modules 到项目仓库,需要注明修改了并且每次拉取代码需要拉取 node_modules
- 使用 patch-package 库,自动化将三方库进行修改和替换(推荐),在 package.json 中修改 git 钩子:postinstall:"patch-package" 使用这个库,使用时在命令行中执行 npm patch-package pkgname
# 网页加载进度条
如何获取进度,如何绘制进度
# 请求方案
- ajax 库
ajax 库基于 xmlHTTPRequest 这个 api,可以通过 event.lengthComputable 获取到对应的进度
- xmlHttpRequest 同上
- fetch
fetch 需要自己手动处理
# 框架中
框架中都有对应的库进行实现
# 前端水印
# 背景
为了保证用户隐私,使得数据相对安全
# 概念
- 明水印
肉眼可见的水印叫做明水印
- 暗水印
对用户无感,但真实存在并发挥作用的水印
# 方案
# 明水印
背景水印
- 生成 svg 图片,作为 body 的背景图
图片水印
- 绘制 canvas
需要注意水印被使用 f12 进行删除,这时可以通过 intersectionObserver 或者 dom.display 等来监听元素的可见度,删除时重新生成水印
# 暗水印
将个人信息写入到文件的二进制代码中,后端通过个人信息进行判断和处理
# 全站请求耗时统计
# 背景
通过这个统计工具,可以更加清晰地看到整个站点地性能情况,首屏加载时间等(FP/FCP)
- 监控请求耗时:HTTP、中间件、axios
- 前端监控,监控整个请求,记录耗时数据
- 后端监控:后端记录
- 数据汇总:数据清洗加工,数据可视化,可视化图表
# 数据上报
- 通过 navigator.sendBeacon 这个 api,进行上报,独立与渲染主进程,不会阻塞页面渲染,页面卸载之后仍然可以上报数据
- 使用 xmlHTTPRequest 或 fetch 进行上报,可以定时定量上报
- 使用 gif 图片上报,但是上报量较少
# 函数式编程思想
# 理念
函数式编程中,函数是一等公民,通过函数封装的方式去解决问题
# 核心概念:
- 函数是一等公民:在函数式编程中,函数被视为一等公民,可以像其他值(如数字、字符串)一样被传递、赋值和返回。这意味着函数可以作为参数传递给其他函数,也可以从函数中返回另一个函数。
- 纯函数(Pure Function):纯函数是指没有副作用的函数,它的输出完全由输入决定,不会改变外部状态或产生其他可见效果。纯函数对于相同的输入始终返回相同的结果,且不会修改原始数据。在函数式编程中,鼓励使用纯函数来处理数据,因为它们易于测试、理解和推理。
- 不可变性(Immutability):函数式编程鼓励使用不可变数据,即数据在创建后不能被修改。当需要对数据进行操作时,函数式编程通常会创建新的数据副本而不是直接修改原始数据。这样可以避免出现意外的副作用和数据竞争,并使代码更加可靠和可维护。
- 高阶函数(Higher-Order Function):高阶函数是指能够接受一个或多个函数作为参数,或者返回一个函数作为结果的函数。JavaScript 中的函数可以作为值进行传递和操作,因此非常适合编写高阶函数。高阶函数可以接收其他函数作为参数,也可以返回新的函数,从而实现函数的组合和抽象。
- 函数组合(Function Composition):函数式编程鼓励使用函数组合来创建复杂功能。函数组合是指将一个函数的输出作为另一个函数的输入,并生成一个新的函数。通过将多个小功能的函数组合在一起,可以形成更复杂的功能,提高代码的可读性和可维护性。
# DNS 域名解析
# DNS 解析慢
1、DNS 预解析
2、使用 CDN,离用户节点近
3、使用外部资源,自己的域名 + oss+cdn
# DNS 劫持
1、HTTPS,加密传输数据的安全性
2、DNSSEC:DNS 安全扩展
# DNS 优化
主要是提升 DNS 缓存,可以使用一下工具测试 dns 速度
1、NSlookup 测试 dns
2、dig 测试 dns
3、在线 dns.google.com 和 dnschecher 等平台测试 dns 速度
# 图片性能优化
- 如果是 http1.0 的版本的话,可以使用精灵图,减少 http 请求,随着 http 并发数量大大增加之后这种方案使用越来越少了
- http2 以上为了使页面加载更快,可以使用图片懒加载,常见的方式有:设置 img 标签的 lazy 属性,和 intersectionObserver 这个 api 和监听 scroll 事件(基本不用)
# 移动端上拉加载,下拉刷新
# 上拉加载
可以设置一个加载图片放在最底部,使用 intersectionObserver 监听它是否可见,如果可见就去加载数据
# 下拉刷新
监听 touch 和 tap 事件,显示刷新的指示器,看有没有达到阈值,如果达到了就触发刷新操作
# 前端页面截图
前端页面截图都是使用第三方库,比如 html2canvas,它们实现的基本原理基本一致:
- 首先通过 svg 的 forginObject 传入对应 dom 的 id, 由于 svg 下载出来不是图片而是 svg 代码,所以需要通过 canvas 进行中转,使用 canvas 的 drawImage 这个 api 去将 svg 画到画布上,去下载 canvas 就行了
# Oauth 授权协议
Oauth 协议是一个关于授权的开放网络标准,它允许用户授权第三方应用访问用户存储在其他服务提供者上的信息,同时不需要讲用户名和密码提供给第三方应用
# 概念
- 资源所有者(用户)
- 用户代理(比如浏览器)
- 第三方应用(客户端)
- 服务提供商(例如 github,提供了授权登录功能)
- 授权服务器(专门用于处理认证授权的服务器)
- 资源服务器(存放用户生成的资源的服务器)
# 方案
# 授权码模式
用户请求登录
- 用户点击登录按钮,被重定向到认证服务器,目的是让用户同意授权三方应用,以访问认证服务器上的某些资源
用户同意授权
- 认证服务器将生成一个授权码并重定向回三方应用
应用请求令牌
- 第三方应用向认证服务器发出请求以交换令牌,请求包括授权码和三方应用的凭证
认证服务器颁发令牌
- 认证服务器验证授权码和应用凭证,如果验证通过,将发放访问令牌给三方应用
访问资源
- 第三方应用使用访问令牌向资源服务器请求,访问用户资源信息
# 客户端模式
客户端以自己的名义,而不是以用户的名义去请求授权接口,获取到 token 后进行请求。
- 客户端模式适用于没有前端的命令行应用,即在命令行下请求令牌
- 直接向授权服务器请求 token
- 获取到 token 之后直接向资源服务器请求资源
# url 重定向适配
# 背景
为了省钱,想要一个链接访问页面,想要同时适配 PC 和 Mobile
# 方案
# 识别端
- 通过 navigator.userAgent 获取到设备信息,添加到请求头中,去进行请求,后端去进行判断,或者:前端根据 navigator.userAgent 判断请求哪一个后端接口
- 通过请求头 User-Agent 进行判断
# 响应式布局
- 通过百分比 + flex 布局配合媒体查询加上 window.onresize 事件去设置元素的设置
- 通过 rem 和 em 加上媒体查询去设置文字的适配
# 处理 QPS 峰值
# 背景
当前端应用的 QPS (每秒查询次数) 达到峰值时,就会对服务器和应用的性能造成很大的压力,甚至可能导致系统崩溃,为了解决这个问题,需要采取一系列措施来优化和管理高并发请求
# 方案
# 请求限流
对请求次数进行限流,以 nodejs 为例可以使用工具 express-rate-limit
# 请求合并
短时间的请求进行合并 (防抖节流), 一次性降低服务端的压力
# 请求缓存
swr 里面针对于请求内容的缓存,里面请求的参数、请求的方法和请求逻辑依赖的内容没有发生变化,直接命中缓存
# 任务队列
针对于请求,我们设计一个任务队列,滑动窗口
# 使用 radius 等内存数据库去缓存数据,降低服务器和数据库的压力
# settimeout 定时器延迟
- settimeout 嵌套层级超过 5 层时,最小设置延迟为 4ms(为了防止 js 引擎过度循环,从而阻塞事件循环)
- 宏任务会在执行栈执行完毕后执行,因此如果到时之后执行栈未执行完毕,就会有一定延迟
- 操作系统调度策略会影响定时器的精度 (例如操作系统可能会优先处理其他任务,导致定时器任务被推迟)
- CPU 时间片会被分配给不同的进程,如果一个进程占用了过多的时间片,就可能会影响定时器的触发时间
- 硬件时钟的精度也会影响定时器的精度 (原子种本身就存在的计时误差)
# 用户数很多时,该从哪些方面思考项目
- 进行 CDN 加速,使得各地的用户都能快速访问到资源,并且 CDN 比 OSS 省钱
- 收集用户行为信息,通过信息优化项目实现迭代,尽可能满足大部分用户
# 扫码登录流程
- 用户发起扫码登陆
- 浏览器请求二维码
- 服务器生成二维码返回给登录页面(具有:唯一标识、重定向的客户端地址、用户状态信息等)
- 登录页面轮询二维码扫描状态
- 用户扫码,确认登录,请求带上用户的 token 更新登录状态
- 服务端轮询到之后生成用户登录 session,返回登录成功