文章目录

腾讯pcg前端日常一面整理笔记(三十二)

1. 介绍一下项目中的虚拟列表功能

答案

项目里的虚拟列表功能,核心是“数据很多,但页面上只渲染可视区附近的节点”。

  1. 根据滚动位置算出当前应该显示的数据范围。
  2. 只渲染这部分数据,其他部分用占位高度撑开滚动条。
  3. 这样可以显著减少 DOM 数量,提升首屏和滚动性能。
  4. 如果是动态高度列表,还要维护高度缓存和偏移量。

2. 为什么要使用虚拟列表

答案

使用虚拟列表的核心原因是:数据量大时,直接渲染全部 DOM 成本太高。

  1. 节点过多会导致首次渲染慢。
  2. 滚动时布局和绘制压力也会变大。
  3. 虚拟列表通过限制真实渲染节点数量,显著降低性能压力。

3. 了解过 Vue 开源虚拟滚动组件吗

答案

可以回答“了解过,而且核心思想和自己实现的思路是一致的”。

  1. 常见开源方案都是按可视区裁剪渲染。
  2. 不定高场景一般会维护高度缓存和偏移表。
  3. 面试里重点不是背组件名,而是讲清核心原理和取舍。

4. 窗口缩放导致高度变化,高度缓存表如何处理

答案

如果列表项高度会受容器宽度变化影响,窗口缩放后原来的高度缓存可能失效。

  1. 需要在 resize 后重新测量受影响项。
  2. 更新高度缓存表和偏移量。
  3. 为了避免频繁重算,一般会做节流或只重算可视区附近项。

5. 用什么 API 和事件测量元素高度

答案

常见方案有两类:

  1. 直接测量:getBoundingClientRectoffsetHeight
  2. 监听变化:ResizeObserver

如果是响应式场景,ResizeObserver 往往更适合持续追踪高度变化。


6. 移动端小游戏适配到桌面端正常游玩

答案

这种适配题可以从输入、布局和性能三方面回答。

  1. 输入层要适配鼠标和键盘,不只支持触摸。
  2. 布局层要考虑宽高比、横竖屏和桌面分辨率。
  3. 还要处理素材尺寸、事件映射和性能差异。

7. 什么是事件冒泡和事件捕获

答案

事件传播分为捕获阶段、目标阶段和冒泡阶段。

  1. 捕获阶段从外层祖先往目标元素走。
  2. 冒泡阶段从目标元素再往外层祖先回传。
  3. 默认大多数监听注册在冒泡阶段。

8. 数组和链表的区别

答案

数组和链表的区别主要在访问方式和增删成本。

  1. 数组内存通常更连续,随机访问快。
  2. 链表插入删除局部节点更方便,但随机访问慢。
  3. JavaScript 里的数组在引擎层面不是简单“纯链表”或“纯原生数组”,而是做了很多优化的动态结构。

9. JS 数组底层是数组还是链表

答案

JavaScript 引擎里的数组不是简单的“纯链表”或“纯原生数组”,而是做了很多优化的数据结构。

  1. 在元素连续、类型稳定时,会尽量按高效数组方式处理。
  2. 如果出现稀疏索引、频繁删除或类型混乱,内部优化策略会退化。

10. 浏览器计时器适合用什么数据结构

答案

浏览器计时器通常会用优先队列或最小堆一类结构管理。

  1. 这样可以快速拿到最近一个应该触发的定时器。
  2. 插入新定时器和弹出最早触发任务的效率都比较高。

11. 最小堆是什么、底层如何实现

答案

最小堆是一种完全二叉树结构,要求父节点值不大于子节点值。

  1. 堆顶始终是最小值。
  2. 插入时通过上浮调整,删除堆顶后通过下沉调整。
  3. 常用于优先队列、定时器调度、TopK 等场景。

12. requestAnimationFrame 是什么、作用

答案

requestAnimationFrame 是浏览器提供的按帧调度 API。

  1. 它会在下一次重绘前执行回调。
  2. 适合动画、滚动同步、增量渲染这类和绘制节奏强相关的场景。
  3. 比纯 setTimeout 更贴近浏览器渲染时机。

13. 大模型输出快慢对 RAF 的优劣势

答案

如果大模型输出特别快,逐 token 刷新可能导致频繁重渲染。

  1. 这时 requestAnimationFrame 可以把多次更新合并到一帧里,减少抖动。
  2. 如果模型输出很慢,RAF 的优势就没那么明显,简单批量更新也够用。
  3. 本质是用 RAF 把 UI 更新节奏和浏览器绘制节奏对齐。

14. 如何平衡 RAF 在不同输出频率下的表现

答案

可以做“缓冲 + 条件刷新”策略。

  1. 高频输出时用 RAF 合并一帧内的多次更新。
  2. 低频输出时可以直接更新,减少等待。
  3. 本质是根据输出频率动态切换刷新策略。

15. Vue nextTick 是什么、作用

答案

nextTick 的作用是等 Vue 完成一次 DOM 更新后,再执行回调。

  1. 因为 Vue 的响应式更新通常是异步批量执行的。
  2. 所以如果你修改了状态后立刻读 DOM,拿到的可能还是旧值。
  3. 这时用 nextTick 可以确保拿到更新后的 DOM。

16. 如何结合 nextTick 优化流式渲染

答案

流式渲染通常是“服务端持续返回分片,前端边收边渲染”。

  1. 服务端按 chunk 或事件流持续输出内容。
  2. 前端通过 EventSourcefetch + ReadableStream 或封装 SDK 持续读取数据。
  3. 每拿到一段内容,就追加到消息状态里,再触发局部更新。
  4. 为了避免频繁重渲染,通常会做分帧刷新、批量合并更新或按 token 缓冲后再刷。

17. 如何解决 Markdown 渲染抖动

答案

Markdown 流式渲染抖动,通常是因为每次只来一点数据就整段重新解析和重渲染。

  1. 可以对 token 做缓冲,按帧或按块刷新,而不是每个字符都重算。
  2. 对于已经稳定的内容尽量复用,只更新尾部增量部分。
  3. 复杂内容可以拆成块级组件,减少整棵树反复重建。

18. 增量渲染能否解决抖动

答案

Markdown 流式渲染抖动,通常是因为每次只来一点数据就整段重新解析和重渲染。

  1. 可以对 token 做缓冲,按帧或按块刷新,而不是每个字符都重算。
  2. 对于已经稳定的内容尽量复用,只更新尾部增量部分。
  3. 复杂内容可以拆成块级组件,减少整棵树反复重建。

19. JS 垃圾回收机制

答案

JavaScript 垃圾回收的核心是判断对象是否仍然可达。

  1. 主流引擎以标记清除为基础。
  2. 现代实现通常还会加分代回收、增量回收、并行回收。
  3. 业务里更重要的是主动清理定时器、事件监听和不再需要的大对象引用。