Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CSR(Client Side Rendering)网页首帧优化总结 #33

Open
Genluo opened this issue Aug 31, 2019 · 1 comment
Open

CSR(Client Side Rendering)网页首帧优化总结 #33

Genluo opened this issue Aug 31, 2019 · 1 comment

Comments

@Genluo
Copy link
Owner

Genluo commented Aug 31, 2019

前言

我们发现随着javascript的出现优化前端开发流程,同时也为前端开发带来新的问题,一个典型的问题就是使用CSR(客户端渲染)出现的首屏白屏问题,首屏白屏将极大的影响用户的操作体验所以为了解决这个问题,我们分析react实现和浏览器渲染页面的相关过程,我们提出如下几种解决方案:

  • 预渲染
  • SSR
  • 同构

下面我们将依次介绍这几种解决方案,通过对比这几种方法,我们找出最适合项目的解决方案。

CSR(Client Side Rendering)

CSR就是:html 仅仅作为静态文件,客户端端在请求时,服务端不做任何处理,直接以原文件的形式返回给客户端客户端,然后根据 html 上的 JavaScript,生成 DOM 插入 html,这就是问题产生的根源,因为浏览器需要执行js才能生成DOM并且将产生的DOM插入到html,但是结合网络性能和客户端渲染相关规则,所以造成首屏白屏问题,为了解决这个问题,我们将通过几种方法来解决这个问题,但是为什么不直接选择不使用CSR?

服务器渲染流程图

为什么不直接不是使用CSR方案?
  • 首先白屏问题只产生在第一次打开页面的时候,不是普遍现象
  • 这是一种前后端分离的手段,可以使得前端专注于UI,后端专注于逻辑
  • 这种前端有更大的作为,因为可以局部进行刷新,可以实现单页应用,预加载等提升页面性能,提高用户体验
  • 可以降低服务器压力,并且部署比较简单,节约服务器成本
  • 为日后有可能进行全端开发留下余地

SSR(server side render)

这种指传统的 ASP、Java 或 PHP 的渲染机制;比如说cnode.js这个项目,这个和客户端渲染中的同构渲染是两个不同的概念,一个对应的是传统 Java、PHP 或 ASP 的渲染机制,另一种则是使用 node.js(理论上可以使用其他语言)把在客户端使用的组件在服务端渲染成 HTML 文本。

服务器端渲染的有优点
  • 服务端渲染可以做到更细粒度的缓存控制(页面上公共的部分一次渲染后后续直接输出)
  • 服务端渲染不用关心浏览器兼容性问题
  • 服务端渲染不需要先下载一堆 js 和 css 后才能看到页面(首屏性能)
  • 对于电量不给力的手机或平板,减少在客户端的电量消耗很重要

预渲染

这里主要说下美团网 - 最佳实践,下面是美团网预渲染流程图

预渲染流程图

我们将整个页面整个页面渲染分成三个部分,FP(First Paint)、FCP(First Contentful Paint)、FMP(First Meaningful Paint),常规CSR三个阶段中FP通常只有一个根节点,FCP阶段包含页面的基本框架,但是没有数据内容,FMP阶段通常包含页面所有元素及其数据。CSR出现的白屏问题就是在FP阶段出现的问题,如果我们能将FCP或者FMP渲染生成的html文档提前到FP阶段进行渲染,用户就能够看到页面框架,也就不会出现相应的白屏问题。- 预渲染思路

为了实现这种预先渲染的方案,那么我们需要使用node作中间层,在项目构建编译时,完成对原始模板的更新和替换,整个项目的流程入下:

开发阶段:

  • 通过 TypeScript 的装饰器单行引入预渲染构建触发的方法。
  • 发布前修改编译构建的配置文件。

发布阶段:

  • 先进行常规的项目构建
  • 若有预渲染相关配置,则触发预渲染构建
  • 通过预渲染得到最终的文件,并完成发布上线动作
自己的思考

但是我认为这种方式治标不治本,因为我们通过将FCP阶段产生的内容提前到FP阶段中,但是这种方式并不能和动态数据进行交互,所以如果整个页面都是静态数据,那么这种方式是完美的,但是如果整个页面或者页面的部分是需要获取动态数据的,那么这样我们发现这种开发方式并不是十分完美的,因为仍有可能造成页面因为数据而抖动,所以我认为预渲染并没有在本质上解决这个问题。

同构

同构是为了解决CSR遇见的问题才出现的,同构是14年出现,成为当时框架一大亮点,同构是针对单页应用SEO优化乏力,首屏速度瓶颈等问题而产生的解决方案,近年来在react和Vue等前端技术栈中都得到了支持,同构是客户端首次请求进行服务器端渲染,结合缓存处理来解决首屏速度瓶颈问题。

React实现同构的过程

核心是React中拥有虚拟DOM的概念,因为存在虚拟DOM,所以React可以脱离浏览器进行渲染,相关流程如下:

服务器端渲染需要把React的初次渲染放到服务器,让React帮我们把业务Component翻译成string类似的DOM,然后通过IO返回给到客户端。

我们来看 React 官方给我们提供的服务端渲染的API:

  • React.renderToString 是把 React 元素转成一个 HTML 字符串,因为服务端渲染已经标识了 reactid,所以在浏览器端再次渲染,React 只是做事件绑定,而不会将所有的 DOM 树重新渲染,这样能带来高性能的页面首次加载!同构黑魔法主要从这个 API 而来。
  • React.renderToStaticMarkup,这个 API 相当于一个简化版的 renderToString,如果你的应用基本上是静态文本,建议用这个方法,少了一大批的 reactid,DOM 树自然精简了,在 IO 流传输上节省一部分流量。

配合 renderToStringrenderToStaticMarkup 使用,createElement 返回的 ReactElement 作为参数传递给前面两个方法。那么我们要实现同构渲染主要解决这几个问题:

实现React作为服务器端渲染的中间件

首先为了实现服务器端渲染需要封装一个中间件,实现React的后端渲染,调用React的服务器端渲染方法生成对应的字符串,然后组装放回给客户端请求。

实现React-router 和后端router统一
实现异步数据的处理
同构带来的好处:
  1. 有助于 SEO
  2. 共用前端代码,节省开发时间
  3. 提高首屏性能
同构带来的坏处:
  1. 性能
  2. 不容忽视的服务器端和浏览器环境差异
  3. 内存溢出
  4. 异步操作
  5. simple store(redux)
总结

同构这种方式结合CSR和SSR的所有优点,但是也带来新的问题,并且在大型项目中存在一个严重的问题就是Node中很容易成为性能瓶颈,所以大型项目一般不采用同构渲染

自己理想的方式

理想的方式将预渲染和视觉优化结合起来进行预分析,不要使用同构方法,同构的方法带来的问题很大,对于整个项目侵入性很大,

视觉优化

其实针对上述白屏问题,我们也可以通过视觉进行优化,比如可以通过

  1. 分拆打包
  2. 交互优化:使用loading的效果、Skeleton Screen 效果
  3. 部分同构化处理

Next.js 优化总结

Next.js 是时下非常流行的基于 React 的同构开发框架。作者之一就是大名鼎鼎的 Socket.io 的作者 Guillermo Rauch。它有以下几个亮点特别吸引我:

  1. 巧妙地用标准化的解决了请求的问题。同构和页面开发类似,异步是个大难题,异步中难点又在接口请求。Next.js 给组件新增了 getInitialProps 方法来专门处理初始化请求,再也不用手动往页面上塞 DATA 和调用 ReactDOMServer.renderToString
  2. 使用 styled-jsx 解决了 css-in-js 的问题。这种方案虽然不像 styled-component 那样强大,但足够简单,可以说是最小的成本解决了问题
  3. Fast by default。页面默认拆分文件方式打包,支持Prefetch页面预加载

相关资料

@Genluo
Copy link
Owner Author

Genluo commented Aug 24, 2022

Astro 相比 Next.js 可以大幅度减少 JS 代码的体积(90% 以上),同时页面的运行时性能也提升了 30% 以上。除此之外,Astro 不仅支持使用 React 框架,而且支持 Vue、Solid 等在内的各种前端框架,灵活性更高。

https://mp.weixin.qq.com/s/G7b9Dv5xEvnM0AMT1EXKJQ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant