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 文本。
前言
我们发现随着javascript的出现优化前端开发流程,同时也为前端开发带来新的问题,一个典型的问题就是使用CSR(客户端渲染)出现的首屏白屏问题,首屏白屏将极大的影响用户的操作体验所以为了解决这个问题,我们分析react实现和浏览器渲染页面的相关过程,我们提出如下几种解决方案:
下面我们将依次介绍这几种解决方案,通过对比这几种方法,我们找出最适合项目的解决方案。
CSR(Client Side Rendering)
CSR就是:html 仅仅作为静态文件,客户端端在请求时,服务端不做任何处理,直接以原文件的形式返回给客户端客户端,然后根据 html 上的 JavaScript,生成 DOM 插入 html,这就是问题产生的根源,因为浏览器需要执行js才能生成DOM并且将产生的DOM插入到html,但是结合网络性能和客户端渲染相关规则,所以造成首屏白屏问题,为了解决这个问题,我们将通过几种方法来解决这个问题,但是为什么不直接选择不使用CSR?
为什么不直接不是使用CSR方案?
SSR(server side render)
这种指传统的 ASP、Java 或 PHP 的渲染机制;比如说cnode.js这个项目,这个和客户端渲染中的同构渲染是两个不同的概念,一个对应的是传统 Java、PHP 或 ASP 的渲染机制,另一种则是使用 node.js(理论上可以使用其他语言)把在客户端使用的组件在服务端渲染成 HTML 文本。
服务器端渲染的有优点
预渲染
这里主要说下美团网 - 最佳实践,下面是美团网预渲染流程图
我们将整个页面整个页面渲染分成三个部分,FP(First Paint)、FCP(First Contentful Paint)、FMP(First Meaningful Paint),常规CSR三个阶段中FP通常只有一个根节点,FCP阶段包含页面的基本框架,但是没有数据内容,FMP阶段通常包含页面所有元素及其数据。CSR出现的白屏问题就是在FP阶段出现的问题,如果我们能将FCP或者FMP渲染生成的html文档提前到FP阶段进行渲染,用户就能够看到页面框架,也就不会出现相应的白屏问题。- 预渲染思路
为了实现这种预先渲染的方案,那么我们需要使用node作中间层,在项目构建编译时,完成对原始模板的更新和替换,整个项目的流程入下:
开发阶段:
发布阶段:
自己的思考
但是我认为这种方式治标不治本,因为我们通过将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 流传输上节省一部分流量。配合
renderToString
和renderToStaticMarkup
使用,createElement
返回的 ReactElement 作为参数传递给前面两个方法。那么我们要实现同构渲染主要解决这几个问题:实现React作为服务器端渲染的中间件
首先为了实现服务器端渲染需要封装一个中间件,实现React的后端渲染,调用React的服务器端渲染方法生成对应的字符串,然后组装放回给客户端请求。
实现React-router 和后端router统一
实现异步数据的处理
同构带来的好处:
同构带来的坏处:
总结
同构这种方式结合CSR和SSR的所有优点,但是也带来新的问题,并且在大型项目中存在一个严重的问题就是Node中很容易成为性能瓶颈,所以大型项目一般不采用同构渲染
自己理想的方式
理想的方式将预渲染和视觉优化结合起来进行预分析,不要使用同构方法,同构的方法带来的问题很大,对于整个项目侵入性很大,
视觉优化
其实针对上述白屏问题,我们也可以通过视觉进行优化,比如可以通过
Next.js 优化总结
相关资料