Facebook 将对 React 的优化实现到了浏览器!

Stella981
• 阅读 345

点上方蓝字关注公众号「前端从进阶到入院

精选原创好文、进阶交流群助你进入大厂

本文转载自公众号「code 秘密花园」

想要提高一个网页的加载速度是非常困难的,如果你的网站是在使用 JavaScript 渲染的内容,你必须要在网页的加载速度和网页的输入响应能力之间作出权衡:

  • 一次性执行首屏需要执行的逻辑(负载性能好,输入响应能力差)

  • 将复杂的逻辑拆分成更小块的任务执行,以保证对外界输入的响应(负载性能差,输入响应能力好)

为了避免这种取舍,FacebookChromium 中提出并实现了 isInputPending() API,它可以提高网页的响应能力,但是不会对性能造成太大影响。

目前 isInputPending API 仅在 Chromium 的 87 版本开始提供,其他浏览器并未实现。

背景

在现今的 JavaScript 生态中,大多数工作都是在一个线程完成的:主线程。这种设计为开发者提供了一个健壮的执行模型,但是如果脚本执行的时间太长,则用户体验(尤其是响应能力)可能会遭受严重损失。例如,用户正在输入一些内容时, JavaScript 正在执行大量的逻辑,则在这些逻辑完成之前,浏览器都不能处理用户的输入事件。

现在的最佳实践是通过将复杂的逻辑拆分成更小块的任务执行来解决这种问题。在页面加载期间,页面可以运行一些 JavaScript 逻辑,然后将控制权转交给浏览器,这时浏览器可以检测自己的事件队列,看看是不是需要响应用户输入,然后再继续运行 JavaScript ,这种方式虽然会有一些帮助,但是同时也可能会带来其他问题。

每次页面将控制权交还给浏览器时,浏览器都会花费一些时间来检查它的事件队列,处理完事件后再获取下一个 JavaScript 代码逻辑。当浏览器更快地响应事件时,页面的整体加载时间会变慢。而且,用户输交互比较多的情况下,页面加载会非常慢。如果我们不那么频繁地进行上面的过程,那么浏览器响应用户事件所花费的时间就会更长。

Facebook 将对 React 的优化实现到了浏览器!

Facebook 提出的 isInputPending API 是第一个将中断的概念用于浏览器用户交互的的功能,并且允许 JavaScript 能够检查事件队列而不会将控制权交于浏览器。

Facebook 将对 React 的优化实现到了浏览器!

下面我们来具体看一个例子。

一个例子

假设您需要做很多显示阻塞的工作来加载页面,例如,从组件生成标记,分解质数或仅绘制一个很酷的加载微调器。这些中的每一个都分解为一个离散的工作项。使用调度程序模式,让我们勾勒出如何在假设的processWorkQueue()函数中处理我们的工作:

假设你再首屏加载页面时要处理非常多的阻塞逻辑,例如从组件生成标记,分解质数,或者只是绘制一个很酷的加载器动画。这些逻辑都会被分解成一个独立的工作项。使用 scheduler 模式,让我们在一个假设的 processWorkQueue() 函数中处理我们的逻辑:

const DEADLINE = performance.now() + QUANTUM;
while (workQueue.length > 0) {
  if (performance.now() >= DEADLINE) {
    // Yield the event loop if we're out of time.
    setTimeout(processWorkQueue);
    return;
  }
  let job = workQueue.shift();
  job.execute();
}

通过 processWorkQueue() 延时链式调用 setTimeout(),我们使浏览器能够在某种程度上保持对输入的响应,同时仍然在相对不间断地运行。但是,可能需要很长时间才能完成其他需要控制事件循环的工作,或者使 QUANTUM 事件延迟增加一毫秒。

在RAIL模型下,QUANTUM 一个好的值是<50ms,这取决于要完成的工作类型。该值主要决定了处理能力和延迟之间的平衡。

但是,我们还可以做的更好:

const DEADLINE = performance.now() + QUANTUM;
while (workQueue.length > 0) {
  if (navigator.scheduling.isInputPending() || performance.now() >= DEADLINE) {
    // Yield if we have to handle an input event, or we're out of time.
    setTimeout(processWorkQueue);
    return;
  }
  let job = workQueue.shift();
  job.execute();
}

通过调用 navigator.scheduling.isInputPending(),我们可以更快地响应输入,同时仍然确保我们的阻塞逻辑能够不间断地执行。如果在完成这些逻辑之前对用户交互(例如绘画)以外的其他操作不感兴趣,则可以方便地增加输入的长度 QUANTUM

默认情况下,“连续”的事件类型不会返回 isInputPending(),比如 mousemovepointermove 等等。如果你对这些也感兴趣的话,没问题。可以通过为 isInputPending() 提供一个包含连续变量为true的字典:

const DEADLINE = performance.now() + QUANTUM;
const options = { includeContinuous: true };
while (workQueue.length > 0) {
  if (navigator.scheduling.isInputPending(options) || performance.now() >= DEADLINE) {
    // Yield if we have to handle an input event (any of them!), or we're out of time.
    setTimeout(processWorkQueue);
    return;
  }
  let job = workQueue.shift();
  job.execute();
}

React 这样的框架正在将 isInputPending() 使用类似的逻辑构建到其核心调度库中。希望这将使使用这些框架的开发人员能够从幕后的 isInputPending() 中受益,而不要进行重大的重写。

React Fiber

让我们回想下 React Fiber 中的时间分片:

把一个耗时长的任务分成很多小片,每一个小片的运行时间很短,虽然总时间依然很长,但是在每个小片执行完之后,都给其他任务一个执行的机会,这样唯一的线程就不会被独占,其他任务依然有运行的机会。

React Fiber 把更新过程碎片化,执行过程如下面的图所示,每执行完一段更新过程,就把控制权交还给 React 负责任务协调的模块,看看有没有其他紧急任务要做,如果没有就继续去更新,如果有紧急任务,那就去做紧急任务。

Facebook 将对 React 的优化实现到了浏览器!

如果你对该库感兴趣,可以到 https://github.com/WICG/is-input-pending 参与反馈和讨论。

参考:https://web.dev/isinputpending/

不得不说 React 团队还是非常强的,一个 JavaScript 库能带动浏览器的发展。虽然这还是第一个由 Facebook 贡献给浏览器的能力,不过未来可期,让我们期待更多更强大的 API 吧!

1.关注「前端从进阶到入院」,获取我分类整理的原创精选面试热点文章。

2. 加我好友,拉你进氛围贼好的前端进阶讨论群,2021 陪你一起度过。

Facebook 将对 React 的优化实现到了浏览器!

分享给你的朋友是最好的支持~

本文分享自微信公众号 - 前端从进阶到入院(code_with_love)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Easter79 Easter79
2年前
Vue 3.0 公开源码后,有人说这也能算 TypeScript ?
点上方蓝字关注公众号「前端从进阶到入院」精选原创好文、进阶交流群助你进入大厂本文转自公众号「工业聚」前言在2019年10月5日,尤小右公开了Vue3.0的源代码。vue 3.0 源代码仓库https://github.com/vuejs/vuenext想了解vue3.0源码的同学,可以访
Easter79 Easter79
2年前
Vue CLI 是如何实现的
点上方蓝字关注公众号「前端从进阶到入院」精选原创好文助你进入大厂文章转载自公众号「玩相机的程序员」!(https://oscimg.oschina.net/oscnet/298a297ae9ec4945aed9d914185449be.png)若微信中阅读体验不佳,可点击阅读原文在PC端阅读。VueCLI是一个基于
Stella981 Stella981
2年前
2021 最顶级 React 组件库推荐
点上方蓝字关注公众号「前端从进阶到入院」作者丨MaxRozen译者丨王强策划丨小智AntDesign!(https://oscimg.oschina.net/oscnet/a85c35f23bd04e5da6a1e5e68a24119b.png)项目链接:AntDesignh
Stella981 Stella981
2年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
可莉 可莉
2年前
2021 最顶级 React 组件库推荐
点上方蓝字关注公众号「前端从进阶到入院」作者丨MaxRozen译者丨王强策划丨小智AntDesign!(https://oscimg.oschina.net/oscnet/a85c35f23bd04e5da6a1e5e68a24119b.png)项目链接:AntDesignh
Wesley13 Wesley13
2年前
CSS 奇思妙想:超级酷炫的边框动画
点上方蓝字关注公众号「前端从进阶到入院」精选原创好文助你进入大厂文章转载自公众号「iCSS前端趣闻」今天逛博客网站shoptalkshow\1\,看到这样一个界面,非常有意思:!(https://oscimg.oschina.net/oscnet/9655b35af5a045999ff55c144a3f7c
Stella981 Stella981
2年前
Docker 部署SpringBoot项目不香吗?
  公众号改版后文章乱序推荐,希望你可以点击上方“Java进阶架构师”,点击右上角,将我们设为★“星标”!这样才不会错过每日进阶架构文章呀。  !(http://dingyue.ws.126.net/2020/0920/b00fbfc7j00qgy5xy002kd200qo00hsg00it00cj.jpg)  2
Stella981 Stella981
2年前
React Core Team 成员开发的「火焰图组件」技术揭秘。
点上方蓝字关注公众号「前端从进阶到入院」精选原创好文、进阶交流群助你进入大厂前言最近在业务的开发中,业务方需要我们性能监控平台提供火焰图来展示函数堆栈以及相关的耗时信息。根据BrendanGregg在FlameGraph\1\主页中的定义:Flamegraphsareavisualizati
Stella981 Stella981
2年前
React 组件逻辑复用的那些事儿
点上方蓝字关注公众号「前端从进阶到入院」,精选原创好文助你进入大厂。基本每个开发者都需要考虑逻辑复用的问题,否则你的项目中将充斥着大量的重复代码。那么React是怎么复用组件逻辑的呢?本文将一一介绍React复用组件逻辑的几种方法,希望你读完之后能够有所收获。如果你对这些内容已经非常清楚,那么略过本文即可。我已尽量对文中的