3.20远程前端开发面试问题记录

334 阅读39分钟
  1. socket 快速推送数据过来可能是秒级,可能是毫秒级,数据量可能大可能小,如何在保证数据即时性的同时优化性能,让 DOM渲染不卡顿?
  2. 做个简单的自我介绍
  3. 谈谈你对水合的理解以及SSR的时候服务端返回的 html 如何跟前端 js 进行水合的?
  4. React中为什么不能再if里面使用hook?
  5. 说说浏览器强缓存和协商缓存
  6. 你进行首屏优化的时候FPS控制在多少指标
  7. 在性能优化方面你做过哪些性能优化都展开说说,不限制vue和react
  8. react和vue中key的作用是什么?原理是什么
  9. SSR的时候首屏加载都会遇到短暂白屏你怎么处理
  10. SSR都会遇到非短暂白屏你怎么处理
  11. 首屏渲染优化你是怎么做的 其他不记得了~~可能是我会的,只记得这几个印象深刻的了

以下是答案

1. react和vue中key的作用是什么?原理是什么

image.png 使用index造成多余的DOM更新,当key相同内容不同的时候会重新更新dom,但如果嵌套输入框,输入框又不会重新更新,如果输入框里面有值则值就会发送错乱 requestIdleCallback

2. react为什么不能再if里面使用hook

在 React 中,Hook 不能在 if 语句、循环或嵌套函数中调用的主要原因是 React 依赖 Hook 的调用顺序来正确管理状态。这条规则由 React 官方明确规定,并且由 eslint-plugin-react-hooks 插件进行检查。 大白话:react的hooks都具有特定的执行顺序,if改变了hook原本的执行顺序,让状态管理变得混乱和不可预测

核心问题:Hook 调用的顺序必须一致

React 通过 调用顺序(Call Order) 来管理每个组件的 Hook,如果 Hook 在 if 语句或循环中使用,可能会导致调用顺序变化,从而引发 状态错乱

示例:错误的 Hook 使用

function MyComponent(props) {
  if (props.show) {
    useState(0); // ❌ 错误,Hook 在 if 语句中
  }
  return <div>Test</div>;
}

假设 props.show 初始为 trueuseState(0) 被调用,但如果 props.show 变为 falseuseState 将不会再被调用,导致 React 失去对 Hook 顺序的追踪,从而引发 状态错乱


正确的使用方式

React 期望 Hook 在组件的 顶层作用域 调用,确保它们始终按照相同的顺序执行:

function MyComponent(props) {
  const [count, setCount] = useState(0); // ✅ Hook 在组件顶层

  if (props.show) {
    console.log("show is true");
  }

  return <div>Count: {count}</div>;
}

这样,不管 props.showtrue 还是 falseuseState(0) 总是会按照固定顺序调用,React 才能正确管理状态。


如何在条件中使用 Hook?

虽然 Hook 不能直接放在 if 语句中,但你可以使用 条件逻辑 来决定是否使用某个状态或副作用:

方案 1:条件值

function MyComponent({ show }) {
  const [count, setCount] = useState(0);
  const message = show ? "显示内容" : "隐藏内容";

  return <div>{message}</div>;
}

这种方式不会破坏 Hook 调用顺序,但仍然能根据 show 的值来调整渲染内容。


方案 2:使用自定义 Hook

如果你确实需要基于条件使用某个 Hook,可以封装成 自定义 Hook,然后在顶层调用:

function useConditionalEffect(show) {
  useEffect(() => {
    if (show) {
      console.log("Effect is running");
    }
  }, [show]);
}

function MyComponent({ show }) {
  useConditionalEffect(show);
  return <div>Test</div>;
}

这样 useConditionalEffect 始终会在组件的顶层调用,避免了 Hook 顺序改变的问题


方案 3:使用 useMemouseEffect

对于 useEffectuseMemo 等 Hook,你可以直接在回调内部处理逻辑:

function MyComponent({ show }) {
  useEffect(() => {
    if (show) {
      console.log("Show is true");
    }
  }, [show]); // ✅ 依赖 show,确保 Hook 顺序不变

  return <div>Test</div>;
}

这样 useEffect 总是按照相同的顺序执行,但内部逻辑会根据 show 进行调整。


总结

Hook 只能在组件的顶层作用域调用,不能放在 if、循环或函数内部,以确保 Hook 调用顺序始终一致。
可以在 Hook 内部使用条件逻辑,如 useEffectuseMemo,避免 Hook 直接出现在 if 语句中。
可以使用自定义 Hook,将条件逻辑封装起来,让 Hook 始终在顶层被调用。

这样能保证 React 正确管理状态,避免意外的 bug 🚀

3.强缓存和协商缓存

强缓存(Strong Cache)与协商缓存(Negotiated Cache)详解

1. 强缓存(Strong Cache)

强缓存是指浏览器在一定时间内直接从本地缓存读取资源,而不会向服务器发送请求。只有当缓存过期或因某些因素失效时,才会向服务器请求最新资源。

1.1 关键 HTTP 头

强缓存主要通过以下 HTTP 响应头 进行控制:

  • Expires
  • Cache-Control
1.2 具体实现
  1. Expires(HTTP/1.0,已逐渐被 Cache-Control 替代)

    • Expires 头的值是一个绝对时间(GMT 格式)。
    • 例如: Expires: Fri, 29 Mar 2025 12:00:00 GMT
    • 表示资源在 2025 年 3 月 29 日 12:00 之前,浏览器无需向服务器请求资源,而是直接从缓存读取。
    • 缺点
      • 受客户端时间影响,如果本地时间错误,可能导致缓存失效或过早过期。
  2. Cache-Control(HTTP/1.1,优先级高于 Expires

    • Cache-Control 头提供更精细的缓存控制,主要指令包括:
      • max-age=<seconds>:表示资源在 X 秒内 直接使用缓存,无需请求服务器。
      • public:可以被任何缓存存储(如 CDN)。
      • private:仅浏览器可缓存,CDN 不能缓存。
      • no-cache:浏览器必须向服务器请求验证资源是否过期(即协商缓存)。
      • no-store:不进行缓存,每次都请求服务器。
    • 例如: Cache-Control: max-age=3600, public
      • 表示 3600 秒(1 小时)内浏览器不会重新请求资源。
1.3 使用场景
  • 适用于静态资源(CSS、JS、图片、字体)

    • 例如:
      • https://example.com/style.css
      • https://example.com/logo.png
    • 服务器返回: Cache-Control: max-age=86400
      • 资源会在 24 小时内(86400 秒) 从缓存加载,减少服务器请求,提高页面加载速度。
  • CDN 资源(例如字体、JS 库)

    • CDN 一般会设置较长的 max-age,如: Cache-Control: max-age=31536000, public
      • 资源会被缓存 一年(31536000 秒),减少带宽使用。

2. 协商缓存(Negotiated Cache)

协商缓存是在浏览器请求资源时,向服务器发送请求,但服务器会验证资源是否更新,如果没有更新,则返回 304 状态码,浏览器继续使用缓存的资源。

2.1 关键 HTTP 头

协商缓存使用以下 请求头 & 响应头

  • Last-Modified / If-Modified-Since
  • ETag / If-None-Match
2.2 具体实现
  1. Last-Modified / If-Modified-Since

    • 服务器响应头: Last-Modified: Fri, 22 Mar 2025 10:00:00 GMT

      • 表示资源最后修改时间为 2025 年 3 月 22 日 10:00。
    • 浏览器请求头: If-Modified-Since: Fri, 22 Mar 2025 10:00:00 GMT

      • 浏览器向服务器询问:“自从 3 月 22 日 10:00 之后,资源有没有更新?
    • 服务器响应

      • 如果资源没变: HTTP/1.1 304 Not Modified
        • 服务器告诉浏览器资源未修改,继续使用缓存。
      • 如果资源已更新: HTTP/1.1 200 OK Last-Modified: Fri, 23 Mar 2025 10:00:00 GMT
        • 服务器返回新资源,并更新 Last-Modified 头。
  2. ETag / If-None-Match(更精确的缓存机制)

    • ETag 是资源的唯一标识符(哈希值),如果资源改变,ETag 也会变。
    • 服务器响应头: ETag: "abc123"
    • 浏览器请求头: If-None-Match: "abc123"
    • 服务器响应
      • 资源未修改: HTTP/1.1 304 Not Modified
        • 继续使用缓存。
      • 资源已修改: HTTP/1.1 200 OK ETag: "xyz789"
        • 返回新资源。
2.3 使用场景
  • 适用于动态内容(HTML、API 数据)

    • 例如:
      • https://example.com/news.html
      • https://api.example.com/data
    • 服务器返回: Last-Modified: Fri, 22 Mar 2025 10:00:00 GMT
    • 如果内容没变,服务器返回 304,节省带宽,提高加载速度。
  • 适用于 CDN 或用户敏感数据

    • ETag 适用于文件精确比较,如果一个资源可能被多个用户修改,ETag 能更可靠地识别更新,如: ETag: "file-version-1"

3. 强缓存 vs 协商缓存对比

特性强缓存(Strong Cache)协商缓存(Negotiated Cache)
是否发送请求❌ 不发送请求,直接使用缓存✅ 发送请求,服务器验证
服务器负载✅ 低(减少请求)⚠️ 略高(需要处理 304)
响应速度✅ 快(无需等待服务器)⚠️ 略慢(需服务器验证)
控制方式Expires / Cache-ControlLast-Modified / ETag
适用场景静态资源(JS、CSS、图片)动态内容(HTML、API)

4. 具体案例

案例 1:静态资源(强缓存)
HTTP/1.1 200 OK
Cache-Control: max-age=31536000, public
  • 资源 一年内 直接使用缓存,不请求服务器。
案例 2:动态数据(协商缓存)
HTTP/1.1 200 OK
ETag: "data-123456"
Last-Modified: Mon, 25 Mar 2025 10:00:00 GMT
  • 浏览器下次请求时: If-None-Match: "data-123456" If-Modified-Since: Mon, 25 Mar 2025 10:00:00 GMT
  • 如果数据没变,返回 304,节省流量。

5. 总结

  • 强缓存(Strong Cache):完全不请求服务器,适用于 静态资源
  • 协商缓存(Negotiated Cache):请求服务器验证,适用于 动态数据
  • 实际应用
    • 静态资源(CSS、JS、图片)强缓存
    • HTML 页面、API 数据协商缓存

合理使用缓存策略,可以优化性能、减少服务器压力,提高网站加载速度 🚀

4.谈谈你对nextjs水合的理解

如果我作为面试官,询问对Next.js中水合(Hydration)的理解,期望得到以下内容的答案:

1. 概念解释

  • 定义阐述:面试者应清晰指出在Next.js的服务器端渲染(SSR)场景中,水合指的是在服务器将React组件渲染为HTML并发送到客户端后,客户端JavaScript代码与已有的HTML进行“融合”,使静态的HTML转变为可交互的React应用的过程。形象地说,就像是给静态的HTML“注入活力”,让它能够响应用户操作,实现完整的交互功能。

2. 工作原理

  • 渲染过程描述:要说明服务器首先使用ReactDOMServer等方法将React组件渲染为HTML字符串,这个HTML包含了页面的基本结构和初始数据。当浏览器接收到这个HTML后,会加载Next.js应用的客户端JavaScript代码。客户端代码中的React会重新挂载组件,并将其与服务器渲染生成的HTML进行比对。通过比对,React能够确定哪些部分需要更新,哪些部分可以复用已有的HTML结构,然后为这些元素添加事件监听器等交互功能,从而实现页面的交互性。例如,服务器渲染出一个包含按钮的列表页面,客户端水合时会给按钮添加点击事件处理函数,使其能在用户点击时执行相应逻辑。
  • 差异处理机制:提及React如何高效处理服务器渲染的HTML与客户端重新渲染的差异。React利用虚拟DOM技术,通过对比服务器端生成的虚拟DOM和客户端重新生成的虚拟DOM,找出最小的差异集,并仅更新实际需要改变的部分,避免不必要的DOM操作,提高水合的效率和性能。

3. 重要性及优势

  • 性能方面:阐述水合对于提升应用性能的作用。由于服务器端已经生成了HTML,用户可以快速看到页面内容,然后通过水合逐步增强页面的交互性,这种方式极大地减少了首屏加载时间,提升了用户体验。与完全在客户端渲染的应用相比,用户无需等待所有JavaScript代码下载、解析和执行完毕才能看到页面内容,特别是在网络环境较差或设备性能较低的情况下,优势更为明显。
  • SEO友好:说明水合与SEO的关系。服务器端渲染生成的HTML可被搜索引擎爬虫直接抓取,而水合过程不会影响搜索引擎对页面内容的索引。这使得采用Next.js进行SSR和水合的应用在搜索引擎优化方面具有显著优势,能够提高网站在搜索结果中的排名。

4. 可能遇到的问题及解决方法

  • 水合不匹配问题:能指出在水合过程中可能出现的“水合不匹配”错误。这通常是由于服务器端和客户端渲染的结果不一致导致的,比如在服务器端和客户端执行代码的环境不同,或者数据获取逻辑存在差异。解决方法可以包括确保服务器端和客户端使用相同的数据、在客户端渲染前进行数据校验和同步,以及避免在服务器端和客户端执行依赖于不同环境的代码等。
  • 性能优化:讨论如何进一步优化水合性能,如代码拆分,将JavaScript代码拆分成更小的块,按需加载,减少初始加载的代码量,从而加快水合速度;还可以通过合理使用next/script组件来控制脚本的加载顺序和时机,确保关键脚本优先加载,提高水合效率。
  • 1. 什么是水合(Hydration)?

水合(Hydration)是指在 服务器端渲染(SSR) 后,客户端的 JavaScript 重新接管并激活静态 HTML,使其变为可交互的页面 的过程。

  • SSR 场景下,服务器返回的是已经渲染好的 HTML,但其中的事件监听等动态交互逻辑 尚未生效
  • 客户端的 JS(React/Vue等框架)会重新解析 HTML 结构并绑定事件,这个过程就是 水合(Hydration)

2. SSR 中服务端返回的 HTML 如何与前端 JS 进行水合?

💡 SSR 水合的核心流程

  1. 服务器渲染 HTML

    • 服务端(Node.js/Next.js/Nuxt.js) 运行 React/Vue 组件,并生成 完整的 HTML 页面
    • 服务器返回的 HTML 结构和客户端的 React/Vue 组件渲染结果一致
  2. 前端加载并执行 JavaScript

    • 浏览器解析 HTML 后,会加载 bundle.js(客户端 JS 代码)。
    • 前端 React/Vue 框架在 window.onloadDOMContentLoaded 事件后执行。
  3. 框架执行 Hydration(对 HTML 结构进行重新绑定)

    • React/Vue 会对比 HTML 结构,发现页面已经有完整的 DOM,而不是空白页面。
    • React 使用 ReactDOM.hydrate(),Vue 使用 createSSRApp() 来复用已有 DOM,避免二次渲染。
  4. 绑定事件监听,激活交互逻辑

    • 例如 <button> 标签已经在 HTML 中,但它的 onClick 事件 需要 JS 重新绑定,否则用户点击不会生效。
    • 这一步完成后,页面就完全恢复到 CSR(客户端渲染)的状态。

3. React SSR 的 Hydration 实现

React 中,SSR 渲染时通常使用 ReactDOM.hydrate() 来进行水合:

import React from "react";
import { hydrateRoot } from "react-dom/client";
import App from "./App";

// 服务器已经返回了 HTML,只需要绑定事件
hydrateRoot(document.getElementById("root"), <App />);

🔹 hydrateRoot()复用已有的 HTML 结构,并绑定事件,而不会重新创建整个 DOM。


4. Vue SSR 的 Hydration 实现

Vue 3 SSR 中,我们使用 createSSRApp() 来激活页面:

import { createSSRApp } from "vue";
import App from "./App.vue";

const app = createSSRApp(App);
app.mount("#app");

🔹 Vue 的 createSSRApp()复用服务端渲染的 HTML,并仅仅为其绑定事件,不会重新生成 DOM。


5. 为什么 SSR 水合可能会导致问题?

(1) 可能出现 "内容不匹配" 错误

如果 服务器返回的 HTML 与客户端渲染的 HTML 不一致,会导致 React/Vue 重新渲染整个页面,甚至出现警告:

Warning: Text content did not match. Server: "Hello" Client: "Hi"

❌ 错误示例(SSR 与 CSR 内容不一致)

// 服务器端渲染
<p>{new Date().toISOString()}</p>

// 客户端渲染
<p>{new Date().toLocaleString()}</p>

🔹 解决方案:确保 SSR 和 CSR 逻辑一致,避免 Math.random()new Date() 这种在客户端和服务端不同步的变量。


(2) SSR 水合会导致页面短暂不可交互

hydrate() 之前,页面虽然有 HTML,但事件未绑定,导致短暂无法交互
🔹 解决方案:骨架屏(Skeleton Screen) + 渐进增强(Partial Hydration)


(3) SSR 页面可能变得更慢
  • 水合过程中,React/Vue 需要重新绑定事件,如果页面很大,JS 计算量大,水合时间会较长
  • 解决方案:
    1. 代码拆分(Code-Splitting)
    2. 选择性水合(Selective Hydration)
    3. 流式渲染(Streaming Rendering)(React 18 新特性)

6. 进阶:如何优化 SSR Hydration 过程?

✅ 方式 1:选择性水合(Selective Hydration)

React 18 允许 局部水合,即 只激活用户交互的部分,而不是整个页面

import { createRoot, hydrateRoot } from 'react-dom/client';

hydrateRoot(document, <App />, {
  onHydrated: () => console.log("Hydration completed"),
});

🔹 这样可以加速交互的可用性


✅ 方式 2:流式渲染(Streaming SSR)

React 18,支持流式 HTML 传输,客户端 按需水合

import { renderToPipeableStream } from 'react-dom/server';

const { pipe } = renderToPipeableStream(<App />, {
  onShellReady() {
    pipe(res);
  },
});

🔹 流式渲染可以更快让页面可见,同时逐步绑定交互逻辑。


7. 结论

  • SSR Hydration 是将服务器返回的 HTML 变成可交互页面的过程
  • React 使用 hydrateRoot(),Vue 使用 createSSRApp() 进行水合
  • 避免 CSR 和 SSR 渲染不一致,否则会导致 水合失败页面被重新渲染
  • 优化方案:选择性水合、流式渲染、代码拆分,提升 SSR 页面性能。

🚀 掌握 SSR Hydration 原理和优化技巧,可以在面试和项目开发中脱颖而出!

5.做一个简单的自我介绍

在面试中,一个精彩的自我介绍能迅速吸引面试官的注意,展现你的专业能力和沟通表达能力。你的简历已经非常优秀,我建议你突出你的核心竞争力、项目经验和亮点技术,同时保持逻辑清晰、简洁流畅

🎯 自我介绍的结构

  1. 简要介绍个人背景(1-2 句话)
  2. 概括你的技术栈和核心能力(3-4 句话)
  3. 突出关键项目经历和技术亮点(3-4 句话)
  4. 总结你的个人特质和职业目标(1-2 句话)

💡 示例:

👋 开场 "您好,我是 [你的名字],一名拥有 9 年经验的前端开发工程师,擅长 Vue、React、Angular,并在多个企业级项目中负责前端架构设计和团队协作。"

💻 技术能力 "我的技术栈涵盖 Vue 生态(Vue2/Vue3、Vuex/Pinia)、React 生态(React Hooks、Redux/Zustand、Next.js),以及跨端开发(React Native、Taro、UniApp)。在工程化方面,我熟悉 Webpack、Vite、Rollup,并在多个项目中主导过性能优化和 CI/CD 流程改进。"

🏆 关键项目经历 "在 [悦居生活智慧社区服务平台] 项目中,我主导 Vue2 迁移 Vue3,优化前端架构,提升代码复用率 40%,并通过 Vite 替换 Webpack,使构建速度提高 80%。
在 [威胁检测平台] 项目中,我优化了百万级数据的渲染性能,使用虚拟列表减少 DOM 开销,使日志加载时间减少 70%。
此外,我在多个项目中实践了前端低代码方案、自研组件库,并优化了 WebSocket 实时通信性能。"

🎯 个人优势 & 发展目标 "我不仅关注技术实现,还注重团队协作和工程化提升,曾负责 3 人前端团队的技术规划和 Code Review 机制。未来,我希望在前端架构、性能优化、微前端等方向持续深入,同时带领团队构建更高效、可扩展的前端体系。"

💪 结束语 "期待在贵公司能有更多技术上的挑战,与团队共同进步,谢谢!"


✨ 如何让面试官觉得你的表达能力强?

  1. 逻辑清晰,条理分明(使用“我擅长 A、在 B 项目做了 C、优化了 D”这种结构)。
  2. 突出亮点,避免流水账(强调你的架构能力、性能优化经验、团队管理经验)。
  3. 语速适中,语气自信(不要念简历,而是像分享经历一样流畅表达)。
  4. 适当加入量化数据(如“性能提升 80%”“减少 70% 加载时间”),更具说服力。
  5. 最后表达期待和感谢,给面试官留下良好印象。

这个自我介绍不仅能展现你的技术深度,还能凸显你的沟通能力和职业规划,让面试官对你留下深刻印象!🎯 🚀

6.SSR都会遇到短暂白屏你怎么处理

📌 短暂白屏的原因与解决方案

短暂白屏 指的是页面加载过程中,用户可能会看到短暂的空白状态,随后内容才逐渐出现。这种情况通常发生在 SSR(服务器端渲染)+ Hydration 过程中,或者 CSR(客户端渲染)首屏渲染 过程中。


🔹 1. 短暂白屏的常见原因

✅ 1.1. JavaScript 资源加载延迟

问题:

  • 服务器返回 HTML 后,JavaScript 代码加载较慢,导致 Hydration 迟滞。
  • 如果 JavaScript 资源未及时执行,页面虽然有 HTML 但无交互。
  • 可能的情况:
    • 前端 JS 体积过大,影响加载速度。
    • 网络波动,CDN 资源加载慢

🚀 解决方案:优化 JavaScript 体积

  • 使用 代码拆分(Code Splitting),按需加载:
    const LazyComponent = lazy(() => import("./HeavyComponent"));
    
  • Tree Shaking 移除未使用的代码:
    "sideEffects": false
    

开启 preload 加快关键资源加载

<link rel="preload" href="/app.js" as="script">

使用 fallback 组件

<Suspense fallback={<p>加载中...</p>}>
  <LazyComponent />
</Suspense>

✅ 1.2. 服务器返回 HTML 过慢

问题:

  • 服务器端渲染 HTML 时间过长,导致页面白屏
  • 可能的情况:
    • API 响应慢(数据请求延迟)。
    • SSR 渲染耗时(如数据过大)。
    • 服务器性能低(CPU 负载高)。

🚀 解决方案:并行数据请求

const [data1, data2] = await Promise.all([fetchData1(), fetchData2()]);

缓存 SSR HTML,避免重复渲染

cache.set("homepage", renderedHTML);

使用 stale-while-revalidate 让旧数据可用

Cache-Control: s-maxage=600, stale-while-revalidate

流式渲染(Streaming)

  • React 18 支持流式渲染,减少白屏:
    import { renderToPipeableStream } from "react-dom/server";
    
  • Vue 3 SSR 也支持流式渲染
    import { renderToNodeStream } from "@vue/server-renderer";
    

✅ 1.3. Hydration 过慢

问题:

  • 服务器端返回的 HTML 页面可见,但 React/Vue Hydration 需要时间,导致短暂白屏。
  • Hydration 过程中 React/Vue 需要绑定事件、解析 DOM,这可能会花费几百毫秒。

🚀 解决方案:分块 Hydration(React 18 / Vue 3)

  • 避免一次性 Hydration,改用并行 Hydration
    import { createRoot } from "react-dom/client";
    createRoot(document.getElementById("root"), { hydrate: true });
    

只 Hydration 关键区域

<Suspense fallback={<Loading />}>
  <MainContent />
</Suspense>

避免 Hydration 失败

  • 确保服务器端 HTML 与客户端 UI 一致
  • 避免 Math.random()Date.now() 影响 Hydration。

🔹 2. 短暂白屏的 UI 解决方案

即使优化了服务器渲染速度,我们仍然可以在 UI 设计上减少白屏带来的不良体验

✅ 2.1. 使用 Skeleton 屏(骨架屏)

❌ 不好的做法:

return data ? <Component /> : null;

✅ 改进:

return data ? <Component /> : <Skeleton />;

示例 Skeleton 代码

const Skeleton = () => (
  <div className="skeleton">
    <div className="skeleton-box"></div>
    <div className="skeleton-line"></div>
  </div>
);

骨架屏优点

  • 减少白屏感知,让用户感觉内容正在加载,而不是完全空白。

✅ 2.2. 预渲染(Prefetch + Preload)

预加载资源,加快首屏渲染:

<link rel="preload" href="/main.css" as="style">
<link rel="prefetch" href="/next-page.js">

预加载 CSS、JS,避免资源加载迟滞。


✅ 2.3. 延迟渲染非关键组件

某些不重要的组件可以在页面加载后再渲染

const HeavyComponent = lazy(() => import("./HeavyComponent"));

export default function Page() {
  return (
    <div>
      <Header />
      <Suspense fallback={<Skeleton />}>
        <HeavyComponent />
      </Suspense>
    </div>
  );
}

先加载 Header,HeavyComponent 在后台加载,避免白屏。


✅ 2.4. 在 SSR 中渲染基础 UI 结构

即使数据未加载完成,也应该先渲染页面基本结构,避免全白:

export default function Page({ data }) {
  return (
    <div>
      <h1>欢迎来到我的网站</h1>
      {data ? <Content /> : <p>数据加载中...</p>}
    </div>
  );
}

这样,用户至少能看到标题,而不是完全空白。


📌 3. 解决短暂白屏的最佳实践

问题解决方案
JS 资源加载慢代码拆分、Preload、CDN 加速
服务器端渲染慢并行请求、缓存、流式渲染
Hydration 过慢部分 Hydration、Suspense
用户感知白屏Skeleton 屏、加载动画

🎯 结论

  • 短暂白屏 主要由 JavaScript 加载、SSR 响应慢、Hydration 过慢 导致。
  • 解决方案
    • 优化 JavaScript 体积(代码拆分、Tree Shaking)。
    • 使用 Skeleton 屏(用户不会感觉到白屏)。
    • 开启流式渲染(React 18/Vue 3)。
    • 缓存数据(避免 SSR 重新计算)。
    • 预加载关键资源(减少 FCP 时间)。

如果面试官问你 "SSR 如何优化短暂白屏?",你可以从 技术优化(流式渲染、缓存)、前端优化(Skeleton、预加载) 两个角度全面解答,展示你的架构能力和前端优化思维!🚀

7.SSR都会遇到非短暂白屏你怎么处理

📌 SSR(服务器端渲染)白屏问题及解决方案

💡 什么是 SSR 白屏问题?

SSR(Server-Side Rendering) 应用中,白屏 通常指的是:

  1. 服务器端已经返回 HTML,但前端 Hydration 失败,导致页面无法交互。
  2. 在网络慢或 JavaScript 资源未加载时,用户看到的是空白页面。
  3. 在数据获取失败或错误处理不当时,导致前端无法正确渲染 UI。

🔹 1. SSR 白屏的常见原因

✅ 1.1. 服务器返回的 HTML 和客户端渲染的 DOM 不匹配

  • 服务器端渲染的 HTML 和前端 Hydration 时的 HTML 结构不同,React / Vue 可能会报错: Warning: Hydration failed because the initial UI does not match what was rendered on the server.
  • 原因
    • 服务器端 渲染了动态数据,但前端渲染时数据未同步。
    • 服务器端和客户端使用 不同的时间格式 / 随机数,导致 HTML 不一致。

🚀 解决方案确保服务器端和客户端的渲染逻辑一致

// ❌ 不要这样,Date 每次渲染都会不同
const now = new Date().toLocaleString();

改为在前端动态计算

const [now, setNow] = useState("");
useEffect(() => setNow(new Date().toLocaleString()), []);

✅ 1.2. JavaScript 资源加载失败

  • 服务器端返回的 HTML 可以显示,但 JS 代码未执行,页面无法交互(比如按钮点击无效)。
  • 可能的原因
    • CDN 资源未加载(如 https://cdn.example.com/app.js 404)。
    • JS 解析错误(如 SyntaxError)。
    • 网络问题导致 JS 未下载

🚀 解决方案开启 Service Worker 进行离线缓存

navigator.serviceWorker.register("/sw.js");

在 HTML 添加 onerror 监听

<script src="/app.js" onerror="location.reload();"></script>

检查浏览器 Console 中的错误信息,找出 JS 失败原因。


✅ 1.3. 数据请求失败

  • SSR 依赖的 API 请求失败,导致返回的 HTML 没有正确的内容
  • 症状
    • HTML 结构为空,导致白屏。
    • React / Vue 在 Hydration 过程中崩溃。

🚀 解决方案在服务器端增加错误兜底逻辑

export async function getServerSideProps() {
  try {
    const res = await fetch("https://api.example.com/data");
    if (!res.ok) throw new Error("数据请求失败");
    return { props: { data: await res.json() } };
  } catch (error) {
    return { props: { data: null, error: "获取数据失败,请稍后再试" } };
  }
}

前端组件兜底

export default function Page({ data, error }) {
  if (error) return <p>{error}</p>;
  return <div>{data ? data.title : "加载中..."}</div>;
}

避免 fetchuseEffect 里直接运行

useEffect(() => {
  fetch("/api/data")
    .then(res => res.json())
    .then(setData)
    .catch(() => setError("加载失败"));
}, []);

✅ 1.4. 前端 Hydration 失败

  • SSR HTML 和客户端的 React / Vue 代码不匹配,导致 Hydration 失败,页面无法交互。
  • 错误案例:
export default function Page() {
  return <h1>{Math.random()}</h1>;
}
  • 服务器端 Math.random() 返回的是 0.1234,客户端可能返回 0.5678,导致 React Hydration 失败。

🚀 解决方案在服务器端确保一致性

export default function Page({ randomNumber }) {
  return <h1>{randomNumber}</h1>;
}

export async function getServerSideProps() {
  return { props: { randomNumber: Math.random() } };
}

避免 Hydration 失败

const [random, setRandom] = useState(0);
useEffect(() => setRandom(Math.random()), []);

🔹 2. SSR 白屏的解决方案

问题原因解决方案
HTML 与前端不匹配服务器端动态渲染的数据在客户端不同确保服务器端数据和前端一致
JS 资源未加载网络问题或 JS 解析错误兜底逻辑 + 错误上报
API 请求失败数据获取失败,导致页面为空服务器端兜底 + 前端错误提示
Hydration 失败React / Vue 代码不匹配避免 Math.random() 等动态数据

🔹 3. SSR 预加载 & 骨架屏

白屏问题的另一个优化手段是 “骨架屏 + 预加载”,确保用户体验流畅。

✅ 3.1. 使用骨架屏

在数据请求未完成前,显示 骨架屏(Skeleton Screen),避免白屏:

function Skeleton() {
  return <div className="skeleton-box">加载中...</div>;
}

export default function Page({ data }) {
  if (!data) return <Skeleton />;
  return <div>{data.title}</div>;
}

用户不会看到白屏,而是看到“加载中”动画


✅ 3.2. 预加载关键资源

<link rel="preload" href="/styles.css" as="style">
<link rel="preload" href="/app.js" as="script">

减少 CSS / JS 加载时间,优化首屏渲染


✅ 3.3. 开启 stale-while-revalidate 缓存

Cache-Control: s-maxage=600, stale-while-revalidate

即使 API 请求失败,也能先展示旧数据


🎯 结论

SSR 白屏通常由以下问题导致

  1. HTML 和前端 Hydration 不匹配 → 确保服务器和客户端数据一致。
  2. JavaScript 资源加载失败 → 兜底逻辑 + Service Worker 缓存。
  3. API 请求失败 → 服务器端和前端都要做好错误处理。
  4. Hydration 失败 → 避免 Math.random() 等动态数据。

✅ 最佳实践

  • 使用骨架屏(Skeleton) 代替白屏。
  • 预加载关键资源(Preload) 提升渲染速度。
  • 开启缓存策略(stale-while-revalidate) 确保数据可用。

8.socket 快速推送数据过来可能是秒级,可能是毫秒级,数据量可能大可能小,如何在保证数据即时性的同时优化性能,让 DOM渲染不卡顿?

当 WebSocket 快速推送数据时,为了保证数据的 即时性 但又不让 DOM 渲染 卡顿,需要采用 批量处理、虚拟列表、异步任务分流等策略 来优化性能。


1. 采用 requestAnimationFrame 进行批量渲染

当数据频繁推送时,避免每次都更新 DOM,而是将数据存入队列,利用 requestAnimationFrame 批量处理,每一帧只更新一次,减少渲染压力。

示例

let dataQueue = [];
let isProcessing = false;

socket.on("message", (data) => {
  dataQueue.push(data);
  if (!isProcessing) {
    isProcessing = true;
    requestAnimationFrame(processData);
  }
});

function processData() {
  if (dataQueue.length > 0) {
    updateUI(dataQueue.splice(0, 10)); // 批量更新 10 条,避免一次性渲染过多
    requestAnimationFrame(processData);
  } else {
    isProcessing = false;
  }
}

好处

  • 限制每帧渲染的数据量,避免大数据量瞬间渲染导致卡顿。

2. 使用 Web Worker 处理数据

WebSocket 推送的 数据解析、计算 可能会占用主线程,导致渲染卡顿。可以用 Web Worker 处理计算逻辑,主线程只负责 UI 渲染。

示例

// 主线程
const worker = new Worker("worker.js");

socket.on("message", (data) => {
  worker.postMessage(data); // 发送数据到 Worker
});

worker.onmessage = (event) => {
  updateUI(event.data); // 只处理最终渲染
};

// worker.js(Web Worker)
self.onmessage = (event) => {
  const processedData = processData(event.data);
  self.postMessage(processedData);
};

好处

  • 计算任务在 Worker 中执行,不阻塞主线程,提升渲染流畅度。

3. 使用节流 & 防抖 控制数据更新频率

如果 WebSocket 毫秒级 推送数据,可以使用 节流(throttle)防抖(debounce) 限制更新频率,减少不必要的 UI 变更。

节流:限制更新频率

import throttle from "lodash/throttle";

const updateThrottled = throttle((data) => {
  updateUI(data);
}, 100); // 100ms 内最多更新一次

socket.on("message", (data) => {
  updateThrottled(data);
});

好处

  • 控制数据更新的频率,防止 UI 频繁 re-render。

4. 虚拟列表(Virtual List)

如果 WebSocket 传输的是长列表数据不要一次性渲染全部数据,使用 虚拟列表(Virtual Scroll) 只渲染可视区域的数据。

React 示例(react-window)

import { FixedSizeList as List } from "react-window";

const Row = ({ index, style }) => (
  <div style={style}>Row {index}</div>
);

<List height={500} itemCount={10000} itemSize={35}>
  {Row}
</List>

Vue 示例(vue-virtual-scroller)

<template>
  <RecycleScroller :items="dataList" :item-size="50">
    <template #default="{ item }">
      <div>{{ item }}</div>
    </template>
  </RecycleScroller>
</template>

好处

  • 仅渲染可视区域的内容,即使有 10W+ 条数据 也不会卡顿。

5. 使用 requestIdleCallback 进行非紧急计算

有些数据可能不需要 立即 处理(比如日志记录、统计等),可以用 requestIdleCallback浏览器空闲时 执行。

示例

socket.on("message", (data) => {
  requestIdleCallback(() => logData(data));
});

好处

  • 避免主线程阻塞,提高 UI 响应速度。

6. 避免不必要的 re-render(React/Vue)

在 React/Vue 项目中,如果组件的状态更新过于频繁,可能会导致 重复渲染,可以通过 useMemo / useCallback(React) 或 computed(Vue) 来优化。

React

const memoizedData = useMemo(() => processData(data), [data]);

Vue

computed(() => processData(data));

好处

  • 避免不必要的渲染,减少性能开销。

7. 总结

优化方案适用场景效果
requestAnimationFrame 批量渲染高频推送数据限制每帧渲染量,提升流畅度
Web Worker计算量大的数据处理分离计算,避免主线程阻塞
节流 throttle高频小数据控制更新频率,减少无效渲染
虚拟列表 Virtual List长列表渲染只渲染可视区域,提升滚动性能
requestIdleCallback低优先级任务在空闲时处理数据,提升主线程性能
useMemo / computed避免无效 re-render减少不必要的状态更新

最终效果

数据实时推送,不卡顿,页面渲染流畅! 🚀

9.你进行首屏优化的时候FPS控制在多少指标

在前端开发中,性能优化是提高用户体验的重要环节。我在 Vue、React 以及其他前端框架的开发过程中,做过以下 多个层面 的性能优化,包括但不限于 首屏加载优化、渲染优化、网络优化、资源优化、代码优化 等。以下是详细的展开:


1. 首屏加载优化

(1)优化资源加载

✅ 关键点: 让用户尽快看到页面内容,减少首屏白屏时间。

  • SSR(服务端渲染)
    • Vue 使用 Nuxt.js,React 使用 Next.js,服务端返回完整 HTML,前端执行水合(Hydration),避免客户端渲染造成的白屏。
  • 静态生成(SSG)
    • 对于 SEO 友好的页面,使用 getStaticProps(Next.js)或 Nuxt generate 预渲染 HTML,提高加载速度。
  • 骨架屏(Skeleton Screen)
    • 在数据未加载完成前,展示占位 UI(如骨架屏)降低用户感知的等待时间。

(2)减少首屏 JS 体积

✅ 关键点: 让关键代码尽快执行,非必要代码延迟加载。

  • Code Splitting(代码拆分)
    • 动态引入(Dynamic Import)
    const Component = React.lazy(() => import('./Component'));
    
    • Webpack splitChunks 配置拆分代码,减少主包体积。
  • Tree Shaking(摇树优化)
    • 仅打包用到的代码,移除无用代码。
    • 避免 import * as lodash,而使用 import { debounce } from 'lodash-es'
  • Preload / Prefetch
    • rel="preload" 加载关键资源,rel="prefetch" 预加载未来可能用到的资源。

(3)优化图片加载

✅ 关键点: 图片是首屏加载的重要影响因素,需要合理优化。

  • 懒加载(Lazy Load)
    • <img loading="lazy" />(现代浏览器支持)
    • Vue:vue-lazyload,React:react-lazy-load
  • 使用 WebP 代替 PNG/JPG
    • WebP 体积更小,加载更快。
  • CDN 加速
    • 使用 CDN 提供图片存储,减少服务器压力。

2. 渲染优化

(1)减少 DOM 操作

✅ 关键点: DOM 操作昂贵,避免不必要的回流和重绘。

  • 使用 Virtual DOM
    • Vue/React 通过Diff 算法减少 DOM 更新,避免全量更新。
  • 使用 key 提高 Diff 计算效率
    • v-formap 中使用唯一 key,避免无意义的重渲染。
  • 避免频繁修改样式
    • 使用 classList.add/remove,避免 style 直接赋值导致频繁回流。

(2)优化列表渲染

✅ 关键点: 大数据列表渲染时,避免性能消耗过大。

  • 虚拟列表(Virtual List)
    • 仅渲染可视区域的数据,提升渲染效率。
    • Vue:vue-virtual-scroller,React:react-window
  • 分页加载
    • 使用 Infinite Scroll(懒加载)方式分页加载数据。

(3)减少组件重新渲染

✅ 关键点: 避免无意义的重复渲染,提高性能。

  • React:使用 memo 进行组件缓存
    const MemoComponent = React.memo(MyComponent);
    
  • Vue:使用 keep-alive 缓存组件
    <keep-alive>
      <MyComponent />
    </keep-alive>
    
  • 使用 useCallback / useMemo
    • 避免不必要的函数重新创建,提高性能。

3. 网络优化

(1)减少 HTTP 请求

✅ 关键点: 降低请求数量,提高加载速度。

  • 合并请求(Batch Requests)
    • GraphQL 批量请求 vs RESTful 多次请求。
  • 使用 HTTP2
    • 允许多个请求复用同一个 TCP 连接,减少请求开销。

(2)缓存优化

✅ 关键点: 充分利用浏览器缓存,减少重复请求。

  • 强缓存(Expires / Cache-Control)
    • 设置 Cache-Control: max-age=31536000,让静态资源长期缓存。
  • 协商缓存(ETag / Last-Modified)
    • 资源变更后,浏览器自动重新请求,减少带宽消耗。

(3)CDN 加速

✅ 关键点: 让用户从最近的节点加载资源,提高加载速度。

  • 使用 Aliyun OSS + CDNCloudflare 部署静态资源,提高访问速度。

4. 代码优化

(1)减少主线程阻塞

✅ 关键点: 让 JS 执行更高效,避免影响 UI 线程。

  • 使用 Web Worker
    • 将复杂计算(如音视频处理)放入 Web Worker,避免主线程阻塞。
  • 避免长任务
    • 将任务拆分,使用 requestIdleCallback 处理低优先级任务。

(2)减少 JavaScript 解析和执行

✅ 关键点: 让 JS 加载更快,减少阻塞渲染。

  • 使用 ES 模块
    • <script type="module"> 让浏览器并行解析 JS。
  • 减少 polyfill
    • 只针对老旧浏览器加载 polyfill,提高现代浏览器性能。

5. FPS 和流畅度优化

(1)保持 60 FPS

✅ 关键点: 让动画和交互更流畅。

  • 使用 requestAnimationFrame
    • 替代 setTimeoutsetInterval,让动画帧率与浏览器同步。
  • GPU 加速
    • 使用 will-change: transform 启用 GPU 加速,提升动画流畅度。

(2)减少动画阻塞

✅ 关键点: 让 UI 更新更流畅,不影响交互。

  • 使用 CSS 动画
    • CSS3 transformtop/left 性能更优。
  • 避免 position: fixed 触发回流
    • 使用 transform: translateZ(0) 让元素开启 GPU 加速。

总结

  • 首屏优化:SSR、静态生成、骨架屏、懒加载。
  • 渲染优化:虚拟 DOM、列表优化、减少重渲染。
  • 网络优化:HTTP 缓存、CDN、合并请求。
  • 代码优化:Tree Shaking、Code Splitting、减少 JS 执行时间。
  • FPS 优化requestAnimationFrame、GPU 加速、避免大规模回流。

这套性能优化方案可以针对 Vue、React、甚至原生 JS 开发时使用。你有没有遇到性能瓶颈,我可以帮你分析!😊

10.在性能优化方面你做过哪些性能优化都展开说说,不限制vue和react

在前端开发中,性能优化是提高用户体验的重要环节。我在 Vue、React 以及其他前端框架的开发过程中,做过以下 多个层面 的性能优化,包括但不限于 首屏加载优化、渲染优化、网络优化、资源优化、代码优化 等。以下是详细的展开:


1. 首屏加载优化

(1)优化资源加载

✅ 关键点: 让用户尽快看到页面内容,减少首屏白屏时间。

  • SSR(服务端渲染)
    • Vue 使用 Nuxt.js,React 使用 Next.js,服务端返回完整 HTML,前端执行水合(Hydration),避免客户端渲染造成的白屏。
  • 静态生成(SSG)
    • 对于 SEO 友好的页面,使用 getStaticProps(Next.js)或 Nuxt generate 预渲染 HTML,提高加载速度。
  • 骨架屏(Skeleton Screen)
    • 在数据未加载完成前,展示占位 UI(如骨架屏)降低用户感知的等待时间。

(2)减少首屏 JS 体积

✅ 关键点: 让关键代码尽快执行,非必要代码延迟加载。

  • Code Splitting(代码拆分)
    • 动态引入(Dynamic Import)
    const Component = React.lazy(() => import('./Component'));
    
    • Webpack splitChunks 配置拆分代码,减少主包体积。
  • Tree Shaking(摇树优化)
    • 仅打包用到的代码,移除无用代码。
    • 避免 import * as lodash,而使用 import { debounce } from 'lodash-es'
  • Preload / Prefetch
    • rel="preload" 加载关键资源,rel="prefetch" 预加载未来可能用到的资源。

(3)优化图片加载

✅ 关键点: 图片是首屏加载的重要影响因素,需要合理优化。

  • 懒加载(Lazy Load)
    • <img loading="lazy" />(现代浏览器支持)
    • Vue:vue-lazyload,React:react-lazy-load
  • 使用 WebP 代替 PNG/JPG
    • WebP 体积更小,加载更快。
  • CDN 加速
    • 使用 CDN 提供图片存储,减少服务器压力。

2. 渲染优化

(1)减少 DOM 操作

✅ 关键点: DOM 操作昂贵,避免不必要的回流和重绘。

  • 使用 Virtual DOM
    • Vue/React 通过Diff 算法减少 DOM 更新,避免全量更新。
  • 使用 key 提高 Diff 计算效率
    • v-formap 中使用唯一 key,避免无意义的重渲染。
  • 避免频繁修改样式
    • 使用 classList.add/remove,避免 style 直接赋值导致频繁回流。

(2)优化列表渲染

✅ 关键点: 大数据列表渲染时,避免性能消耗过大。

  • 虚拟列表(Virtual List)
    • 仅渲染可视区域的数据,提升渲染效率。
    • Vue:vue-virtual-scroller,React:react-window
  • 分页加载
    • 使用 Infinite Scroll(懒加载)方式分页加载数据。

(3)减少组件重新渲染

✅ 关键点: 避免无意义的重复渲染,提高性能。

  • React:使用 memo 进行组件缓存
    const MemoComponent = React.memo(MyComponent);
    
  • Vue:使用 keep-alive 缓存组件
    <keep-alive>
      <MyComponent />
    </keep-alive>
    
  • 使用 useCallback / useMemo
    • 避免不必要的函数重新创建,提高性能。

3. 网络优化

(1)减少 HTTP 请求

✅ 关键点: 降低请求数量,提高加载速度。

  • 合并请求(Batch Requests)
    • GraphQL 批量请求 vs RESTful 多次请求。
  • 使用 HTTP2
    • 允许多个请求复用同一个 TCP 连接,减少请求开销。

(2)缓存优化

✅ 关键点: 充分利用浏览器缓存,减少重复请求。

  • 强缓存(Expires / Cache-Control)
    • 设置 Cache-Control: max-age=31536000,让静态资源长期缓存。
  • 协商缓存(ETag / Last-Modified)
    • 资源变更后,浏览器自动重新请求,减少带宽消耗。

(3)CDN 加速

✅ 关键点: 让用户从最近的节点加载资源,提高加载速度。

  • 使用 Aliyun OSS + CDNCloudflare 部署静态资源,提高访问速度。

4. 代码优化

(1)减少主线程阻塞

✅ 关键点: 让 JS 执行更高效,避免影响 UI 线程。

  • 使用 Web Worker
    • 将复杂计算(如音视频处理)放入 Web Worker,避免主线程阻塞。
  • 避免长任务
    • 将任务拆分,使用 requestIdleCallback 处理低优先级任务。

(2)减少 JavaScript 解析和执行

✅ 关键点: 让 JS 加载更快,减少阻塞渲染。

  • 使用 ES 模块
    • <script type="module"> 让浏览器并行解析 JS。
  • 减少 polyfill
    • 只针对老旧浏览器加载 polyfill,提高现代浏览器性能。

5. FPS 和流畅度优化

(1)保持 60 FPS

✅ 关键点: 让动画和交互更流畅。

  • 使用 requestAnimationFrame
    • 替代 setTimeoutsetInterval,让动画帧率与浏览器同步。
  • GPU 加速
    • 使用 will-change: transform 启用 GPU 加速,提升动画流畅度。

(2)减少动画阻塞

✅ 关键点: 让 UI 更新更流畅,不影响交互。

  • 使用 CSS 动画
    • CSS3 transformtop/left 性能更优。
  • 避免 position: fixed 触发回流
    • 使用 transform: translateZ(0) 让元素开启 GPU 加速。

总结

  • 首屏优化:SSR、静态生成、骨架屏、懒加载。
  • 渲染优化:虚拟 DOM、列表优化、减少重渲染。
  • 网络优化:HTTP 缓存、CDN、合并请求。
  • 代码优化:Tree Shaking、Code Splitting、减少 JS 执行时间。
  • FPS 优化requestAnimationFrame、GPU 加速、避免大规模回流。

这套性能优化方案可以针对 Vue、React、甚至原生 JS 开发时使用。你有没有遇到性能瓶颈,我可以帮你分析!😊

11.首屏渲染优化你是怎么做的

首屏渲染优化(First Paint/First Contentful Paint/Time to Interactive)是前端性能优化的重要一环,目标是让用户尽快看到页面的主要内容,提高交互体验。我在 Vue 和 React 项目中做过多种优化,以下是一些关键优化策略:


1. 资源优化(减少加载时间)

(1)静态资源按需加载

  • 代码分割(Code Splitting)

    • Vue:使用 webpackVite 的动态 import() 进行按需加载
    const AsyncComponent = defineAsyncComponent(() => import('@/components/MyComponent.vue'));
    
    • React:使用 React.lazy() + Suspense
    const LazyComponent = React.lazy(() => import('./LazyComponent'));
    
  • 首屏不需要的资源延迟加载

    • 图片懒加载loading="lazy",或者使用 IntersectionObserver
    • 非关键 CSS/JS 延迟加载(如 deferasync

(2)减少 HTTP 请求

  • 使用 HTTP/2 或 HTTP/3 进行多路复用,减少连接开销。
  • 雪碧图(Sprite)合并小图标 或使用 SVG Sprites
  • 字体优化
    • 只加载必要的字体子集(font-display: swap;)。
    • WebFont 预加载 (<link rel="preload" as="font">)。

2. 渲染优化(减少白屏时间)

(1)SSR(服务端渲染)或 SSG(静态生成)

适用于:SEO 需求强的项目

  • Vue:Nuxt.js (nuxt generate)
  • React:Next.js (getServerSideProps() / getStaticProps())

作用

  • 服务器预渲染 HTML,减少前端计算量,提高首屏渲染速度。
  • 但 SSR 需要解决水合(Hydration)问题,避免 CSR 二次渲染造成的白屏。

(2)骨架屏(Skeleton Screen)

适用于:数据量大、接口返回慢的场景

  • Vue:使用 vue-skeleton-loader
  • React:使用 react-loading-skeletonplaceholder

示例:

{loading ? <Skeleton height={40} /> : <h1>{data.title}</h1>}

用户不会看到白屏,而是一个预加载 UI,提高体验。


(3)首屏关键 CSS 提前加载

减少 FOUC(闪烁无样式内容)

  • CSS 提前加载
    <link rel="preload" href="/styles/main.css" as="style" />
    
  • CSS Critical Rendering Path
    • 提取首屏关键 CSS,直接嵌入 <style>,非关键 CSS 采用 lazyload

3. 交互优化(提高可用性)

(1)减少 JavaScript 执行时间

  • 减少不必要的 JavaScript 计算(比如避免大数据遍历)。
  • 使用 requestIdleCallback 让低优先级任务在空闲时间执行
    requestIdleCallback(() => {
      console.log('执行低优先级任务');
    });
    

(2)首屏渲染时减少阻塞

  • 避免 setTimeoutrequestAnimationFrame 影响首屏
  • 使用 defer 让非关键 JS 延迟加载
    <script src="analytics.js" defer></script>
    
  • 优先渲染主内容,推迟非核心部分
    • 例如,在 React/Vue 里先渲染核心 UI,再通过 useEffect 处理次要内容:
    useEffect(() => {
      fetchMoreData();
    }, []);
    

4. 监控与优化

(1)使用 Web 性能指标

  • FP(First Paint):首个像素绘制
  • FCP(First Contentful Paint):首个内容绘制
  • TTI(Time to Interactive):可交互时间
  • LCP(Largest Contentful Paint):最大内容绘制
  • CLS(Cumulative Layout Shift):累积布局偏移

(2)使用性能分析工具

  • Chrome DevTools Performance
  • Lighthouse
  • WebPageTest
  • Google PageSpeed Insights

5. 具体优化实战总结

优化点VueReact作用
代码分割defineAsyncComponentReact.lazy()减少首屏 JS 体积
SSRNuxt.jsNext.js预渲染 HTML,减少前端计算
图片懒加载v-lazyloading="lazy"避免一次性加载所有图片
骨架屏vue-skeleton-loaderreact-loading-skeleton让用户看到占位内容
关键 CSS 提前加载<style> 内嵌<link rel="preload">避免 FOUC
requestIdleCallback低优先级任务异步执行
defer/async非关键 JS 延迟执行
性能监控performance.now()Lighthouse监控与优化

6. 总结

  1. 减少 HTTP 请求(合并资源、使用 CDN、HTTP/2)。
  2. 优化 JS 解析与执行(Tree Shaking、懒加载)。
  3. 减少白屏时间(SSR、骨架屏、关键 CSS)。
  4. 异步加载非核心内容deferrequestIdleCallback)。
  5. 监控性能指标并优化(LCP、CLS、TTI)。

这些优化手段结合使用,可以显著提升首屏加载速度,让用户获得更流畅的体验!🚀