浏览器渲染与 ReactFiber 关系

公众号【码农爱摸鱼】,专注于在摸鱼中愉快的工作和学习~

我们知道 JS 是单线程的,同一时间只能执行一件事情。

而在我们前端使用框架书写页面代码时,就算是大数据量的渲染和 dom 操作,也不会在浏览器上体会出很强的卡顿。

这得力于在我们使用的框架中,均在处理数据和浏览器渲染这俩个事件上做过代码处理已达到减轻或者去除可能会导致浏览器渲染卡顿的情况。

而在 React 中,于 16 版本之后对此渲染处理的模块单独做过优化行成了新的调度策略(Fiber),今天我们就来浅浅的了解一下。

浏览器渲染

首先,咱来了解一下,在浏览器中页面是一帧一帧绘制出来的,当每秒绘制的帧数(FPS)达到 60 时,页面是流畅的,小于这个值时,用户会感觉到卡顿。 1s 60 帧,所以每一帧分到的时间是 1000/60 ≈ 16 ms。所以我们书写代码时力求不让一帧的工作量超过 16ms。

在一帧中浏览器所需要完成的事情

通过图可看到,一帧内需要完成如下六个步骤的任务:

  • 1.处理用户的交互
  • 2.JS 解析执行
  • 3.帧开始。窗口尺寸变更,页面滚去等的处理
  • 4.requestAnimationFrame(rAF)
  • 5.布局
  • 6.绘制

了解了上面的生命周期之后,我们再来看 2 个函数:

requestIdleCallback

上面六个步骤完成后没超过 16 ms,说明时间有富余,此时就会执行requestIdleCallback里注册的任务。 下面是一个简单的示例:

scss 复制代码
requestIdelCallback(task);

function task (deadline) {
  // deadline.timeRemaining()可以获取到当前帧剩余时间
  while (deadline.timeRemaining() > 0 && tasks.length > 0) {
    doWorkIfNeeded();
  }
  if (tasks.length > 0){
    requestIdleCallback(task);
  }
}

requestAnimationFrame

requestAnimationFrame方法就是告诉浏览器你希望执行一个动画。

并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。

该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。

上面这句话引自 MDN

说通俗点就是,该 API 能以浏览器的显示频率来作为其动画动作的频率,例如某一设备的刷新率是 75 Hz,那这时的时间间隔就是 13.3 ms(1 秒 / 75 次),动画回调也每 13.3ms 调用一次;

Fiber

Fiber 架构的功能就是来处理这类渲染问题,其主要思想如下:

  1. 解决主线程长时间被 JS 运算占用这一问题的基本思路,是将运算切割为多个步骤,分批完成。也就是说在完成一部分任务之后,将控制权交回给浏览器,让浏览器有时间进行页面的渲染。等浏览器忙完之后,再继续之前未完成的任务。

  2. React 将任务分成小片,在一小片段的时间内运行这些分片任务,让主线程做优先级更高的事情,如果有任何待处理的事情,就回来完成工作。一个 Fiber 就是一个工作单元, React 的一个核心概念是 UI 是数据的投影 ,组件的本质可以看作输入数据,输出 UI 的描述信息(虚拟 DOM 树),即:

    ui = f(data)

    也就是说,渲染一个 React app,其实是在调用一个函数,函数本身会调用其它函数,形成调用栈,递归调用导致的调用栈我们本身无法控制, 只能一次执行完成。而 Fiber 就是为了解决这个痛点,可以去按需要打断调用栈,手动控制 stack frame------就这点来说,Fiber 可以理解为 virtual stack frame。

  3. 旧版 React 通过递归的方式进行渲染,使用的是 JS 引擎自身的函数调用栈,它会一直执行到栈空为止。而 Fiber 实现了自己的组件调用栈,它以链表的形式遍历组件树,可以灵活的暂停、继续和丢弃执行的任务。实现方式是使用了浏览器的 requestIdleCallback 这一 API。

    而对此,官方的解释是这样的:

window.requestIdleCallback()会在浏览器空闲时期依次调用函数,这就可以让开发者在主事件循环中执行后台和低优先级的任务,而且不会对像动画和输入响应等用户交互这些延迟触发但关键的事件产生影响。函数一般会按先进先调用的顺序执行,除非函数在浏览器调用它之前就到了它的超时时间。

而基于这些思想,最终完成了 Fiber 的优化,至于 Fiber 的核心内容和代码,咱后面再一起继续研究 🧐

我是摸鱼君,你的【三连】就是摸鱼君创作的最大动力,如果本篇文章有任何错误和建议,欢迎大家留言!

文章持续更新,可以微信搜索 【码农爱摸鱼】关注公众号第一时间阅读。

相关推荐
AlienZHOU7 小时前
AI Coding 时代下,我的技术面试实践分享
前端·后端·面试
Captaincc10 小时前
AI用量v0.1.11更新发布 新增 jusage doctor 诊断指令 托盘展示token 和余额 新增 AutoClaw 支持
前端·后端·vibecoding
计算机魔术师11 小时前
德国Wiki被黑后两周,OpenAI终于把模型失控的账本摊开了
前端
kyriewen12 小时前
我让 AI 当面试官面了我一轮:第 3 个追问我就卡住了(附 10 道追问清单)
前端·面试·ai编程
IT_陈寒12 小时前
Python的GIL把我坑惨了,多线程跑得比单线程还慢
前端·人工智能·后端
前端snow12 小时前
ai agent --- 多agent框架之图编排引擎-langgraph
前端
竹林81812 小时前
OmniPic Studio v3.2.1 核心技术架构与全平台发版解析文档
前端·浏览器
JamesZhang8007812 小时前
页面内存只涨不跌? 一次泄漏排查, 牵出 WeakMap 的诞生
前端
Z小明13 小时前
第 6 章 组件进阶
前端·vue.js
江华森13 小时前
HTTP请求的完整过程详解:从DNS解析到TCP挥手的微秒级实战分析
前端