【AICon】探索RAG 技术在实际应用中遇到的挑战及应对策略!AICon精华内容已上线73%>>> 了解详情
写点什么

React 从入门到放弃,一个关于网页速度的故事

  • 2020-09-16
  • 本文字数:3261 字

    阅读完需:约 11 分钟

React从入门到放弃,一个关于网页速度的故事

2011 年的时候,我碰巧找到一份编写Backbone.jsapp 的工作。如果你从没做过那样的工作,千万别去做。我会给那些愿意听我抱怨的人,喋喋不休地讲我遇到的各种困难。当我开始深入研究前端的替代方案时,我发现了FRPFlapjaxClojureScript。其中 ClojureScript 让我迷上了Clojure。我甚至针对 FRP 和 ClojureScript (以及Hoplon的前身 hlisp)做了一场成功的演讲

React

然后在 2013 年的时候,React 发布了。我在我的新工作中尝试了 React,并在 Clojure 主题的峰会(Clojure Cup 2013)期间发现 CLJS 和 React 简直是天作之合。React 为什么这么好呢?对于我来说,主要的卖点是它组件化做的非常好。


当你使用之前的东西,例如 jQuery、Backbone、Angular 或者其它东西,只需一年的开发之后,你的代码就会是一团事件监听器和触发器。千万别让我碰那些莫名其妙的 JS,jQuery 根本就不存在代码封装。哪个处理器在哪里绑定,用来做什么?很难说这是一个好的基础库!


然后我开始在Kasta工作,那里的 web 前端完全就是一团 jQuery 式的玩意儿。没人想要碰那些代码,因为你会花费数小时,甚至数天,来做一些最小的改动。然后 QA 会发现比你想象的多得多的错误状态。然后用户会向我们的呼叫中心报告更多的错误。那糟糕程度简直超乎你的想象。


因此,在进行了一些实验、测试和检查后,我决定使用 React + ClojureScript 技术栈,用 Clojure 进行服务器端渲染。

没落

有一段时间,一切看起来都很好。我们的有这样的架构:我们的组件在后端作为 Clojure 执行,所以没有服务器端 Node.js,太棒了!而且 UX 开发者通过出色的实时重新加载(多亏了 CLJS),能够从编辑器连接到浏览器的 REPL,并直接在编辑器试验。那简直太棒了!


长话短说,我们的前端变得越来越大。增量编译变得越来越慢——现在通常需要一到两秒以上。虽然我们做了一些尝试来保持整个 app 的性能,但最终我们还是失败了。这是一个痛苦的凌迟过程。应用程序变得太大,启动时间变得太长。服务端渲染只能帮助一部分,但是混合渲染会阻塞浏览器。在比较老旧的硬件或 Android 系统上,这变得不可接受!


2016 年的时候,一个主要原因是我们在启动时间上采取了大的改动,拥有了一个没有页面加载且具有大量交互的富 web 应用程序。在一段时间内,这是有效的!但是启动时间越来越长,导致在谷歌的 PageSpeed 上被评为可耻的 5/100(有时会达到 25/100 左右)。


除此之外,在执行下面描述的操作时,我们发现 React 也会导致一些有问题的实践。例如悬停用 JS(而不是用 CSS),下拉菜单用 JS,不渲染(在悬停时)隐藏的文本(谷歌对此会不高兴),奇怪的复杂逻辑等等。你可以创建一个没有这些问题的 React 应用程序,但是显然,你必须比我们有更好的自控能力(人无完人!)。


而且从那之后,我们的绝大部分用户都转向了移动 app。这使得 web app 成为新用户的主要入口。这意味着它的主要目标是为新用户快速渲染页面,因为想要更多功能的老用户现在都在移动 app 上了。而TTI(响应时间)在这里变得更加重要。

变革时刻

既然情况已经改变,那我们要怎么做呢?在 React 出现之前,我读过“我如何靠 vanilla JS 生存”这类的文章,但这些文章通常没有任何意义——它要么是一个关于它有多伟大的喧嚣,而无视所有问题(关注点分散、内聚性、组件化、代码封装),要么是一个(或几个)人在脑袋里想想而没有实际代码的项目。


早在二月的某个时候,我偶然发现了Intercooler.js。我不确定我以前是否见过它——也许我看过但一瞥而过——但这没关系。这一次,它引起了我的注意。


其理念是,所有的 HTML 都在服务器端渲染。而客户端根据元素的属性,更新部分 HTML。基本上类似 HTML+XHR。你不能任意妄为,但这是其重点之一:有些限制是好的,从而让你不会做一些疯狂的事情。你需要服务器的一些支持,这样你就可以渲染部分结果——虽然只是一个优化,但确实非常重要。


还有一个备选库——Unpoly。这个库围绕布局和样式有更多特性,但是在 XHR 上的想法比较少(例如,如果没有表单,很难完成带参数的 POST 请求)。而且这个库大的多。而且它是用 CoffeeScript 编写的,有许多类,这也有点问题


所以我用 Intercooler 对我们的目录页做了一个概念验证式的实现,而且它成功了!除了对 jQuery 有依赖和其它一些令人恼火的东西外…当我纠结于对 HTML 片段的请求时,我明白了一件事:当我为目录页选择技术路线图时,最后的选择是“类似 intercooler 的小东西”。


那为什么还不行动呢?

TwinSpark

我喜欢 Intercooler 在处理 AJAX 方面的流畅方案,所以我决定用一些汽车方面的东西来命名这个库,而 TwinSpark 似乎是一个不错的名字。这具体是个什么东西呢?


TwinSpark是一个用于声明式 HTML 增强的框架:你在元素上添加额外的属性,TwinSpark 对它们对一些处理。例如发起一个 AJAX 调用并用响应替换目标,或者增加一个样式类,或者,你们自己看看这些例子吧。


当然,它与 Intercooler 有些不同之处,不然它为什么会存在?最值得一提的就是,它不依赖 jQuery。它只支持现代浏览器(不支持 IE 和 Opera Mini)而抛弃掉了 88kb 的兼容性怪代码。


它还有以下优点:


  • 没有继承——这点再强调也不过分!

  • 指令有明确的扩展点

  • 支持对服务器的批量请求

  • 更严格的属性命名规范(这是我的观点,但ic-getic-post使我烦恼:别让我改变观点啊!)

  • 负载更小(多亏了没有 jQuery!)

  • 应该更快(也多亏了没有 jQuery)


老实说,最主要的原因是批处理无继承性。继承在这里尤其痛苦。在 Intercooler 中,如果你在 body 中声明ic-target属性,其中的所有标签都会认为它们的 target 也是这个。这样的话,在 HTML 树的某个地方有一个组件,而树上更高位置的一个属性改变了这个组件的行为。我认为这是一个奇怪的动态范围,我可不想要那样!:)


有趣的是,在对 TwinSpark 进行了一个月的尝试之后,Intercooler 的作者宣布它在做一个没有 jQuery 的现代版本:htmx。它有非常好的扩展点,而且可能会增加批处理…但是仍然有继承。:-(

TwinSpark 为什么是一个好主意

我们需要从两个方面看待它:它是否对开发者友好以及它是否对用户友好。React 对前者优化,而对于后者来说是非常讨厌的。


TwinSpark 方案在大部分情况下对用户更友好:更少的 JavaScript,更少的抖动,更常见的类似 HTML 的行为。在最差的情况下,我们将返回 2.5MB 简化后的(但没有 gzip 压缩过的)JS 和 700KB 的目录 HTML(其中一半是 React 的初始化数据)。JS 包那么大不是因为包含的图像、css 或其它一些复杂的东西,而是因为它是整个 app,有很多视图和逻辑。


现在它是 40KB 的简化的没有 gzip 压缩过的 JS(TwinSpark、分析埋点、一些行为代码和 IntersectionObserver 兼容包)和 350KB 的 HTML。两个数量级的差距,而且 HTML 也更小!


在开发者方面,我认为 React 仍然比较好些,但是 TwinSpark 比用 jQuery 在代码封装和组件化方面要好。另外还有很多方法来提升它。


好消息是开发流程没有太大变化!我们仍然编写从站点内存存储中查询必要数据(需要的时候发起一个 API 调用)的组件,但他们只在服务端执行。我们在我们以前的架构中有效地利用了后端,而且这使得我们能够完美地渲染“部分”HTML——因为组件不需要等待某个“controller”来给他们所有必需的数据。这也使得我们可以同时拥有 React 和非 React 版本,进行 A/B 测试,而无需编写二次标签。

结论

从首次尝试到发布,我们花了 4 个月时间。并不是我们刚开始时预想所需的时间(“应该最多需要两三周!”),呵呵,但并不是只有我们这么做。从代码中移除 React 相关代码并将我们的 app 打造成一个服务端应用程序仍然花费了很多时间和精力。它仍然需要一些润色,但我们还是决定发布它来缩短时间。A/B 测试显示我们是对的——特别是对于 Android 手机。


谷歌现在给我们的目录页排名 75/100 而不是 5/100。我想,这还是很不错的吧?:)


作者介绍:


Alexander Solovyov 现在是Kasta公司的首席产品官,之前是那里的 CTO。我们致力于为消费者和生厂商构建一站式电子商务平台。


原文链接:


A tale of webpage speed, or throwing away React


2020-09-16 10:022387

评论

发布
暂无评论
发现更多内容

InfoQ专访 | 联邦学习将会带来数据价值挖掘的下一个爆发点

Jessica@数牍

联邦学习

LeaRun快速开发平台:企业供应链管理系统解决方案

力软低代码开发平台

CloudBees CI使用Velero进行灾备(DR)概念验证

龙智—DevSecOps解决方案

ci 停机时间 灾难恢复计划

跟着官方文档学 Python 之:基础语法

甜甜的白桃

Python 数据类型 7月月更

一、What's API

忠厚

API API Explorer平台 api 网关

万字多图,搞懂 Nginx 高性能网络工作原理!

C++后台开发

nginx 中间件 后端开发 高性能网络 C++开发

干货|语义网、Web3.0、Web3、元宇宙这些概念还傻傻分不清楚?(上)

Orillusion

开源 WebGL 元宇宙 Metaverse webgpu

Klocwork部署的安全最佳实践

龙智—DevSecOps解决方案

klocwork 静态代码分析 SAST工具

影响分析:RubyGems未授权访问漏洞(CVE-2022-29176)

龙智—DevSecOps解决方案

rubygems 漏洞

Spring Security用户定义

急需上岸的小谢

7月月更

一个月后,我们又从 MySQL 双主切换成了主 - 从!

悟空聊架构

MySQL 悟空聊架构 征文活动 7月月更

【C 语言】进阶指针 Five

謓泽

7月月更

P4Python:合并实践指南之如何脚本化integrate流程

龙智—DevSecOps解决方案

文件合并 P4 Perforce Helix Core

基础设施 NFTScan 正式发布 Solana 网络 NFT 浏览器

NFT Research

区块链 NFT

Hive表类型

五分钟学大数据

hive 7月月更

带你认识数仓的“规格变更”

华为云开发者联盟

数据库 后端 集群 数仓

企业知识管理过程中常见的误区与解决方法

Baklib

体验SRCNN和FSRCNN两种图像超分网络应用

华为云开发者联盟

人工智能 图像 图像超分

React + Node.js 全栈实战教程 - 手把手教你搭建「文件上传」管理后台

蒋川

node.js react.js mongodb Express axios

全面掌控!打造智慧城市建设的"领导驾驶舱"

华为云开发者联盟

云计算 后端 智慧城市 智慧屏

都有哪些较好用的项目管理软件?

PingCode

项目管理 项目管理软件

知乎基于 Apache Doris 的 DMP 平台架构建设实践|万字长文详解

SelectDB

Apache 数据库 数据仓库 广告系统 Doris

华为云GaussDB两大数据库通过中国信通院多项评测

华为云开发者联盟

数据库 后端 华为云

卷是真的卷,“粗心马虎”也是真的要扣分

图灵教育

数学 小学 初中

IPA应用探索:基于客户意图交互让业务受理更有“温度”

鲸品堂

运营商

HTTP的前世今生

技术小生

HTTP 7月月更

从工程师到技术leader的思维升级

阿里技术

技术成长

关于FAQ页面的一些制作技巧

Baklib

企业钟情于混合App开发,小程序容器技术能让效率提升100%

Speedoooo

微信小程序 APP开发 跨端开发 小程序容器

DevOps工具链:开放、自由地选择最适合团队和业务需要的工具

龙智—DevSecOps解决方案

DevOps DevOps工具 DevOps工具链

AIRIOT物联网平台助力油库自动化升级 实现业务场景全覆盖

AIRIOT

低代码 物联网 低代码,项目开发

React从入门到放弃,一个关于网页速度的故事_架构_Alexander Solovyov_InfoQ精选文章