前端(3)

77 阅读15分钟

1. 蚂蚁

  1. pc和h5的区别
  2. 选择mobx和redux的理由
  3. 最近遇到的技术,怎么解决的 音频、动画
  4. 请求并发
  5. usePrevious

2. 婚礼纪

  1. 网络缓存策略

1)浏览器缓存策略

浏览器每次发起请求时,先在本地缓存中查找结果以及缓存标识,根据缓存标识来判断是否使用本地缓存。如果缓存有效,则使用本地缓存;否则,则向服务器发起请求并携带缓存标识。根据是否需向服务器发起HTTP请求,将缓存过程划分为两个部分:
强制缓存和协商缓存,强缓优先于协商缓存。

  • 强缓存,服务器通知浏览器一个缓存时间,在缓存时间内,下次请求,直接用缓存,不在时间内,执行比较缓存策略。
  • 协商缓存,让客户端与服务器之间能实现缓存文件是否更新的验证、提升缓存的复用率,将缓存信息中的Etag和Last-Modified
    通过请求发送给服务器,由服务器校验,返回304状态码时,浏览器直接使用缓存。

HTTP缓存都是从第二次请求开始的:

  • 第一次请求资源时,服务器返回资源,并在response header中回传资源的缓存策略;
  • 第二次请求时,浏览器判断这些请求参数,击中强缓存就直接200,否则就把请求参数加到request header头中传给服务器,看是否击中协商缓存,击中则返回304,否则服务器会返回新的资源。

2)强缓存

  • 强缓存命中则直接读取浏览器本地的资源,在network中显示的是from memory或者from disk
  • 控制强制缓存的字段有:Cache-Control(http1.1)和Expires(http1.0)
  • Cache-control是一个相对时间,用以表达自上次请求正确的资源之后的多少秒的时间段内缓存有效。
  • Expires是一个绝对时间。用以表达在这个时间点之前发起请求可以直接从浏览器中读取数据,而无需发起请求
  • Cache-Control的优先级比Expires的优先级高。前者的出现是为了解决Expires在浏览器时间被手动更改导致缓存判断错误的问题。
    如果同时存在则使用Cache-control。

3)强缓存-expires

  • 该字段是服务器响应消息头字段,告诉浏览器在过期时间之前可以直接从浏览器缓存中存取数据。

  • Expires 是 HTTP 1.0 的字段,表示缓存到期时间,是一个绝对的时间 (当前时间+缓存时间)。在响应消息头中,设置这个字段之后,就可以告诉浏览器,在未过期之前不需要再次请求。

  • 由于是绝对时间,用户可能会将客户端本地的时间进行修改,而导致浏览器判断缓存失效,重新请求该资源。此外,即使不考虑修改,时差或者误差等因素也可能造成客户端与服务端的时间不一致,致使缓存失效。

  • 优势特点

    • 1、HTTP 1.0 产物,可以在HTTP 1.0和1.1中使用,简单易用。
    • 2、以时刻标识失效时间。
  • 劣势问题

    • 1、时间是由服务器发送的(UTC),如果服务器时间和客户端时间存在不一致,可能会出现问题。
    • 2、存在版本问题,到期之前的修改客户端是不可知的。

4)强缓存-cache-control

  • 已知Expires的缺点之后,在HTTP/1.1中,增加了一个字段Cache-control,该字段表示资源缓存的最大有效时间,在该时间内,客户端不需要向服务器发送请求。
  • 这两者的区别就是前者是绝对时间,而后者是相对时间。下面列举一些 Cache-control 字段常用的值:(完整的列表可以查看MDN)
    • max-age:即最大有效时间。
    • must-revalidate:如果超过了 max-age 的时间,浏览器必须向服务器发送请求,验证资源是否还有效。
    • no-cache:不使用强缓存,需要与服务器验证缓存是否新鲜。
    • no-store: 真正意义上的“不要缓存”。所有内容都不走缓存,包括强制和对比。
    • public:所有的内容都可以被缓存 (包括客户端和代理服务器, 如 CDN)
    • private:所有的内容只有客户端才可以缓存,代理服务器不能缓存。默认值。
  • Cache-control 的优先级高于 Expires,为了兼容 HTTP/1.0 和 HTTP/1.1,实际项目中两个字段都可以设置。

  • 该字段可以在请求头或者响应头设置,可组合使用多种指令:

  • 可缓存性

    • public:浏览器和缓存服务器都可以缓存页面信息
    • private:default,代理服务器不可缓存,只能被单个用户缓存
    • no-cache:浏览器器和服务器都不应该缓存页面信息,但仍可缓存,只是在缓存前需要向服务器确认资源是否被更改。可配合private,过期时间设置为过去时间。
    • only-if-cache:客户端只接受已缓存的响应
  • 到期

    • max-age=:缓存存储的最大周期,超过这个周期被认为过期。
    • s-maxage=:设置共享缓存,比如can。会覆盖max-age和expires。
    • max-stale[=]:客户端愿意接收一个已经过期的资源
    • min-fresh=:客户端希望在指定的时间内获取最新的响应
    • stale-while-revalidate=:客户端愿意接收陈旧的响应,并且在后台一部检查新的响应。时间代表客户端愿意接收陈旧响应的时间长度。
    • stale-if-error=:如新的检测失败,客户端则愿意接收陈旧的响应,时间代表等待时间。
  • 重新验证和重新加载

    • must-revalidate:如页面过期,则去服务器进行获取。
    • proxy-revalidate:用于共享缓存。
    • immutable:响应正文不随时间改变。
  • 其他

    • no-store:绝对禁止缓存
    • no-transform:不得对资源进行转换和转变。例如,不得对图像格式进行转换。
  • 优势特点

    • 1、HTTP 1.1 产物,以时间间隔标识失效时间,解决了Expires服务器和客户端相对时间的问题。
    • 2、比Expires多了很多选项设置。
  • 劣势问题 :存在版本问题,到期之前的修改客户端是不可知的。

5)协商缓存

  • 协商缓存的状态码由服务器决策返回200或者304
  • 当浏览器的强缓存失效的时候或者请求头中设置了不走强缓存,并且在请求头中设置了If-Modified-Since 或者 If-None-Match 的时候,会将这两个属性值到服务端去验证是否命中协商缓存,如果命中了协商缓存,会返回 304 状态,加载浏览器缓存,并且响应头会设置 Last-Modified 或者 ETag 属性。
  • 对比缓存在请求数上和没有缓存是一致的,但如果是 304 的话,返回的仅仅是一个状态码而已,并没有实际的文件内容,因此 在响应体体积上的节省是它的优化点。
  • 协商缓存有 2 组字段(不是两个),控制协商缓存的字段有:Last-Modified/If-Modified-since(http1.0)和Etag/If-None-match(http1.1)
  • Last-Modified/If-Modified-since表示的是服务器的资源最后一次修改的时间;Etag/If-None-match表示的是服务器资源的唯一标
    识,只要资源变化,Etag就会重新生成。
  • Etag/If-None-match的优先级比Last-Modified/If-Modified-since高。

6)协商缓存-协商缓存-Last-Modified/If-Modified-since

  • 1.服务器通过 Last-Modified 字段告知客户端,资源最后一次被修改的时间,例如 Last-Modified: Mon, 10 Nov 2018 09:10:11 GMT

  • 2.浏览器将这个值和内容一起记录在缓存数据库中。

  • 3.下一次请求相同资源时时,浏览器从自己的缓存中找出“不确定是否过期的”缓存。因此在请求头中将上次的 Last-Modified 的值写入到请求头的 If-Modified-Since 字段

  • 4.服务器会将 If-Modified-Since 的值与 Last-Modified 字段进行对比。如果相等,则表示未修改,响应 304;反之,则表示修改了,响应 200 状态码,并返回数据。

  • 优势特点

    • 1、不存在版本问题,每次请求都会去服务器进行校验。服务器对比最后修改时间如果相同则返回304,不同返回200以及资源内容。
  • 劣势问题

    • 2、只要资源修改,无论内容是否发生实质性的变化,都会将该资源返回客户端。例如周期性重写,这种情况下该资源包含的数据实际上一样的。
    • 3、以时刻作为标识,无法识别一秒内进行多次修改的情况。 如果资源更新的速度是秒以下单位,那么该缓存是不能被使用的,因为它的时间单位最低是秒。
    • 4、某些服务器不能精确的得到文件的最后修改时间。
    • 5、如果文件是通过服务器动态生成的,那么该方法的更新时间永远是生成的时间,尽管文件可能没有变化,所以起不到缓存的作用。

7)协商缓存-Etag/If-None-match

  • 为了解决上述问题,出现了一组新的字段 Etag 和 If-None-Match

  • Etag 存储的是文件的特殊标识(一般都是 hash 生成的),服务器存储着文件的 Etag 字段。之后的流程和 Last-Modified 一致,只是 Last-Modified 字段和它所表示的更新时间改变成了 Etag 字段和它所表示的文件 hash,把 If-Modified-Since 变成了 If-None-Match。服务器同样进行比较,命中返回 304, 不命中返回新资源和 200。

  • 浏览器在发起请求时,服务器返回在Response header中返回请求资源的唯一标识。在下一次请求时,会将上一次返回的Etag值赋值给If-No-Matched并添加在Request Header中。服务器将浏览器传来的if-no-matched跟自己的本地的资源的ETag做对比,如果匹配,则返回304通知浏览器读取本地缓存,否则返回200和更新后的资源。

  • Etag 的优先级高于 Last-Modified

  • 优势特点

    • 1、可以更加精确的判断资源是否被修改,可以识别一秒内多次修改的情况。
    • 2、不存在版本问题,每次请求都会去服务器进行校验。
  • 劣势问题

    • 1、计算ETag值需要性能损耗。
    • 2、分布式服务器存储的情况下,计算ETag的算法如果不一样,会导致浏览器从一台服务器上获得页面内容后到另外一台服务器上进行验证时现ETag不匹配的情况。
  1. html、css、js对应防止的缓存
  2. service worker
  3. mobx跨组件的状态为什么不会引起中间组件的渲染
  • 在使用MobX进行状态管理时,跨组件的状态更新不会引起中间组件的渲染,主要是因为MobX的响应式系统只会追踪和更新那些实际使用了该状态的组件
  • Observable和Observer机制:MobX通过observableobserver来管理状态和组件。observable创建了一个响应式的状态对象,而observer则是一个高阶组件,用于包装那些需要响应状态变化的React组件。只有被observer包装的组件在使用了某个observable状态时,才会在该状态变化时重新渲染。
  • 细粒度追踪:MobX通过Proxy和getter来细粒度地追踪状态的读写操作。当一个组件读取了某个observable属性时,这个组件会被注册为该属性的观察者。当属性发生变化时,只有直接读取了该属性的组件会被通知进行重新渲染,而那些没有直接读取该属性的中间组件则不会被影响
  1. 什么是 React Fiber

React Fiber 是对 React 核心算法的一次重新实现,旨在使 React 能够更好地处理复杂的 UI 更新。Fiber 架构引入了一种增量渲染的机制,使得 React 能够将渲染工作分解成更小的任务,从而在执行这些任务时可以更好地响应用户交互和动画。

  • Fiber 节点
    • 每个 React 元素都会对应一个 Fiber 节点。Fiber 节点是一个 JavaScript 对象,包含了组件的类型、属性、子组件、DOM 引用等信息。
    • Fiber 节点形成一个树结构,代表了 React 应用的虚拟 DOM 树。
  • 增量渲染
    • 传统的 React 渲染是一个同步的、不可中断的过程。Fiber 引入了增量渲染,使得渲染过程可以被分成多个小的任务,每次执行一部分任务,从而允许在渲染过程中插入其他高优先级的任务(如用户交互)。
  • 优先级调度
    • Fiber 引入了优先级的概念,每个更新任务都被赋予一个优先级。React 会根据任务的优先级决定先执行哪些任务,从而提高应用的响应速度。
  • 双缓冲机制
    • Fiber 树有两棵:当前屏幕上显示的树(current tree)和正在构建的树(work-in-progress tree)。React 在构建新的 Fiber 树时,不会立即修改当前树,直到新的树准备好替换旧树。

Fiber 架构的工作流程

  1. 调度阶段(Reconciliation)

    • 在这个阶段,React 会根据当前的应用状态和更新请求来构建新的 Fiber 树。这个过程是可中断的,React 可以在必要时暂停这个过程来处理更高优先级的任务。
  2. 渲染阶段(Commit)

    • 一旦新的 Fiber 树构建完成,React 会将变化提交到 DOM。这是一个同步的、不可中断的过程。在这个阶段,React 会更新 DOM、调用生命周期方法(如 componentDidMountcomponentDidUpdate)等。

优势

  1. 可中断的渲染

    • 通过将渲染工作分解成小任务,React 可以在必要时暂停渲染以处理更高优先级的任务,从而提高应用的响应速度。
  2. 优先级调度

    • React 可以根据任务的优先级决定先执行哪些任务,这使得用户交互和动画能够更加流畅。
  3. 更细粒度的更新控制

    • Fiber 使得 React 能够更细粒度地控制更新过程,从而提高性能。
  4. IoC 的主要特点

    **IoC(Inversion of Control,控制反转)**是一种设计原则,主要用于提高代码的灵活性和可维护性。它的核心思想是将对象的创建和管理的控制权从应用程序代码中反转出来,由框架或容器来管理。

    1. 控制反转:传统的程序中,代码直接控制对象的创建和生命周期,而 IoC 则将这部分控制权交给框架或容器。
    2. 依赖注入:IoC 的一种常见实现方式,通过依赖注入(Dependency Injection)将依赖的对象传递给需要它们的类,而不是在类内部直接创建依赖。
    3. 提高松耦合性:通过 IoC,可以降低类之间的耦合度,使得系统更加灵活,易于扩展和维护。
    • 构造函数注入:在创建对象时通过构造函数传递依赖。

    • 属性注入:通过设置对象的属性来注入依赖。

    • 方法注入:通过方法参数传递依赖。

  5. 项目是如何发布到线上的,用户是怎么使用最新版本的

  • 构建和打包

    • 使用 Webpack 或其他构建工具进行打包,生成优化后的静态文件(如 bundle.jsindex.html)。
  • 上传到服务器

    • 使用 FTP/SFTP 或 CI/CD 工具(如 Jenkins、GitHub Actions)将静态文件上传到服务器。
  • 部署到 Web 服务器

    • 将静态文件放置在 Web 服务器(如 Nginx、Apache)指定的目录中,确保服务器配置正确以服务这些文件。

用户使用最新版本

  1. 缓存控制

    • 文件名哈希:通过 Webpack 配置文件名哈希(如 bundle.[hash].js),确保文件更新时,用户能获取到新文件。
    • Cache-Control 头:在 Web 服务器上设置合适的 Cache-Control 头,控制缓存策略。对于需要频繁更新的文件,使用较短的缓存时间。
  2. 版本管理

    • HTML 文件更新:每次构建后更新 HTML 文件中的引用路径,确保指向最新的打包文件。
    • 清除旧缓存:在部署新版本时,通知用户清除浏览器缓存,或者通过版本查询和对比,强制刷新。
  3. 服务更新通知

    • WebSocket 或 SSE:通过 WebSocket 或服务器发送事件通知用户有新版本发布,用户可以选择刷新页面以获取最新版本。