CSR、SSR、Prerender原理全解密

CSR、SSR、Prerender原理全解密

2023年6月29日发(作者:)

CSR、SSR、Prerender原理全解密做前端的同学们肯定或多或少听说过CSR ,SSR ,Prerender 这些名词,但是⼤多肯定只是停留在听说过,了解过,略懂⼀点,但是,你真的理解这些技术吗?这些名词具体是什么意思呢?为什么会产⽣这种技术,要解决的问题是什么呢?每种技术背后的原理⼜是什么呢?从各⾃的概念和执⾏流程说起在了解这些概念之前,我们要先了解⼀个熟知的概念,那就是 SPA(Single Page Application) ,没错,就是⼤家熟知的单页应⽤,其实 CSR、SSR、Prerender 都是基于 SPA ,关于 SPA 的概念我就不多阐述了。CSR(Client Side Render)(客户端渲染)即,渲染过程全部交给浏览器进⾏处理,服务器不参与任何渲染。打包下来页⾯是这个样⼦:流程:浏览器 --> 服务器 --> (⽩屏) --> --> images --> Render我们来使⽤ create-react-app 来建⽴⼀个 web ⼯程,并在 Chrome ⾥使⽤ slow 3G ⽹络下做个实验:可以看到,从页⾯空⽩到元素绘制⽤了⾜⾜ 12 秒左右,这个⽩屏时间太可怕了,这也就是为什么在 Web App 盛⾏的当下,包体积越来越⼤会导致⽩屏时间越来越长,⼤家想要优化这个现象的原因。Prerender(Pre Render)(预渲染)即,打包的时候就预先渲染页⾯,所以在请求到 就已经是渲染过的内容流程:浏览器 --> 服务器 --> (预渲染的内容) --> Render --> + images --> Render我们将刚刚的⼯程加⼊ prerender-spa-plugin 这个插件,再次运⾏看看结果这次打包下来的主页 html 是这个样⼦的:⾸页就已经预渲染好了,这时我们再来运⾏⼀次看看:此时可以看到,页⾯只⽤了 2 秒就已经渲染出元素,不会造成长时间的⽩屏问题SSR(Server Side Render)(服务器渲染)流程:浏览器 --> 服务器 --> 服务器执⾏渲染 --> (实时渲染的内容)) --> Render --> + images -->Render可见 SSR 在服务端多做了⼀些实时渲染的操作,那么我们这次运⾏下来回事什么结果呢?可以看出来,SSR 和 Prerender 的效果⼀致,都能很好的减少⽩屏时间总结从上⾯的实验,可以看出来,⽆论是 SSR 还是 Prerender ,我们要解决的问题主要是⽩屏时间太长的问题,这两种技术都是为了解决 CSR 的不⾜之处,那么这两种⽅案有什么区别?使⽤场景⼜有哪些呢?P.S 其实另⼀⽅⾯的原因是,CSR 对 SEO 太不友好了,搜索引擎抓取不到关键信息,只能抓取⼀个毫⽆元素的⽩屏页⾯,会导致搜索引擎搜索不到你的页⾯信息进⾏推荐,SSR 和 Prerender 都能很好的解决这个问题。(吐槽⼀下:Google 已经实现了抓取基于 SPA 的 CSR )Prerender or SSR在做出选择之前,我们必须要充分的了解两者的差异。Prerender 更加通⽤但是局限性太⼤der 原理是在构建阶段就将 html 页⾯渲染完毕,不会进⾏⼆次渲染,也就是说,当初打包时页⾯是怎么样,那么预渲染就是什么样,如果页⾯上有数据实时更新,那么浏览器第⼀次加载的时候只会渲染当时的数据,等到 JS下载完毕再次渲染的时候才会更新数据更新,会造成数据延迟的错觉。der 需要预先指定需要渲染的页⾯,需要⼿动在 webpack ⾥设置 所以页⾯数量很⼤的情况下,想将每个页⾯进⾏预渲染是很⼤⼯作量,⽽且打包时间会很长,还可能会遗漏说了那么多利弊,那么,预渲染是怎么做到⽣成页⾯的呢?做过爬⾍的同学肯定知道 headless 的概念Headless Chrome 在 Chrome59 中发布,⽤于在 headless 环境中运⾏ Chrome 浏览器,也就是在⾮ Chrome 环境中运⾏ Chrome。它将 Chromium 和 Blink 渲染引擎提供的所有现代 Web 平台功能引⼊命令⾏。它有什么⽤处呢?headless 浏览器是⾃动测试和服务器环境的绝佳⼯具,您不需要可见的 UI shell。例如,针对真实的⽹页进⾏测试,创建⽹页的 PDF,或者只是检查浏览器如何呈现 URL。Prerender 就是利⽤ Chrome 官⽅出品的 Puppeteer ⼯具,对页⾯进⾏爬取。它提供了⼀系列的 API, 可以在⽆ UI 的情况下调⽤ Chrome 的功能, 适⽤于爬⾍、⾃动化处理等各种场景。它很强⼤,所以很简单就能将运⾏时的 HTML 打包到⽂件中。原理是在 Webpack 构建阶段的最后,在本地启动⼀个 Puppeteer 的服务,访问配置了预渲染的路由,然后将Puppeteer 中渲染的页⾯输出到 HTML ⽂件中,并建⽴路由对应的⽬录。下⾯是流程图SSR 虽好但是要框架⽀持⽬前来说,主流的框架 React 、Vue 都已经⽀持 SSR ,只是配置会繁琐点,有⼈就会疑惑,框架还要⽀持 SSR ?可事实是,正是因为现代 SPA 的 Virtual DOM 的存在,才能使 SSR 变成现实,但是,SSR 这种理念的实现,并⾮易事。我们先来看看详细的 SSR 流程图:可以看出,SSR 和 Prerender 的最⼤区别就在于,Prerender 是静态的,SSR 是动态的,SSR 会在服务端实时构建出对应的 DOM 。这也是 SSR 的难点所在:同构(即服务器和浏览器共同构建)。何为同构同构这个概念存在于 Vue ,React 这些新型的前端框架中,同构实际上是客户端渲染和服务器端渲染的⼀个整合。我们把页⾯的展⽰内容和交互写在⼀起,让代码执⾏两次。在服务器端执⾏⼀次,⽤于实现服务器端渲染,在客户端再执⾏⼀次,⽤于接管页⾯交互。上⾯我们说过,SSR 的⼯程中,React 代码会在客户端和服务器端各执⾏⼀次。你可能会想,这没什么问题,都是Java 代码,既可以在浏览器上运⾏,⼜可以在 Node 环境下运⾏。但事实并⾮如此,如果你的 React 代码⾥,存在直接操作 DOM 的代码,那么就⽆法实现 SSR 这种技术了,因为在 Node 环境下,是没有 DOM 这个概念存在的,所以这些代码在 Node 环境下是会报错的。但是就是由于 Virtual DOM 技术的存在,让这⼀切变成了可能,这⾥不过多介绍 Virtual DOM ,简单来说,它就是⼀个普通的 JS 对象,只不过映射了 HTML DOM 的结构,React 在做页⾯操作时,实际上不是直接操作 DOM ,⽽是操作Virtual DOM ,也就是操作普通的 Java 对象,这就使得 SSR 成为了可能。我们可以直接在代码⾥判断当前的运⾏环境,如果是浏览器,就可以直接操作 DOM ,如果是服务器,就需要使⽤Virtual DOM ⽣成 HTML 字符串。到了这⾥仿佛⼀切都很简单,⼀切都这么顺其⾃然,但是问题⼜出现了,路由怎么办浏览器路由和服务器路由完全是两种不同的运⾏机制,SPA 浏览器路由机制可以看这⾥,其实原因很简单,在服务器端需要通过请求路径,找到路由组件,⽽在客户端需通过浏览器中的⽹址,找到路由组件,是完全不同的两套机制,所以这部分代码是肯定⽆法公⽤。所以 React 分别为浏览器端和服务器端分别提供了 BrowserRouter 和 StaticRouter 两种路由,通过 BrowserRouter 我们能够匹配到浏览器即将显⽰的路由组件,对浏览器来说,我们需要把组件转化成 DOM ,所以需要我们使⽤ ⽅法来进⾏ DOM 的挂载。⽽ StaticRouter 能够在服务器端匹配到将要显⽰的组件,对服务器端来说,我们要把组件转化成字符串,这时我们只需要调⽤ ReactDom 提供的 renderToString ⽅法,就可以得到 App 组件对应的 HTML 字符串。那么,现在差不多要完成了吧还没有!对于⼀个 React 应⽤来说,路由⼀般是整个程序的执⾏⼊⼝。在 SSR 中,服务器端的路由和客户端的路由不⼀样,也就意味着服务器端的⼊⼝代码和客户端的⼊⼝代码是不同的。⽽⼊⼝则是 Webpack 进⾏打包完成的。针对代码运⾏环境的不同,要进⾏有区别的 Webpack 打包,我们需要在 Webpack 的配置中加⼊ target: 'node' ,表明是服务器环境进⾏打包,除此之外,还有各种各样的配置需要解决。等等,万⼀要⽤到 Redux 来进⾏状态管理呢如果要⽤到 redux 进⾏全局状态管理,⼀定要记得写成这种形式:因为服务器端的 Store 是所有⽤户都要⽤的,但是不能让所有⽤户共享 Store ,所以在服务器端渲染中,Store 的创建应该像下⾯这样,返回⼀个函数,每个⽤户访问的时候,这个函数重新执⾏,为每个⽤户提供⼀个独⽴的 Store 。最后还有什么注意点吗由于服务器不存在挂载元素这⼀⽣命周期,所以例如 React 的 componentDidMount 或者 VUE 的 mounted ⽣命周期都由于服务器不存在挂载元素这⼀⽣命周期,所以例如 React 的 componentDidMount 或者 VUE 的 mounted ⽣命周期都不会执⾏了,所以在服务端利⽤接⼝获取数据的时候,不能写⼊上述的⽣命周期中。最后总结1.如果页⾯⽆数据,或者是纯静态页⾯,建议使⽤ Prerender ,这是⼀种通过预览打包的⽅式构建页⾯,也不会增加服务器负担,但其他情况并不推荐。2.当访问量过⼤时, SSR 的实时构建会加剧服务器 CPU 的消耗,需结合其他技术进⾏处理(例如 CDN,服务器缓存,负载均衡等)3.如果页⾯数据请求多,⼜对 SEO 和加载速度有需求的,建议使⽤ SSR4.对于⾼操作需求的项⽬来说, CSR 可能更加适合,页⾯显⽰元素即绑定了操作,⽽ SSR 和 Prerender 虽然会提前显⽰页⾯,但此时页⾯元素⽆法操作,仍需要下载完 进⾏事件绑定才能执⾏当然在真正实现 SSR 架构的过程中,难点有时不是实现的思路,⽽是细节的处理。⽐如说如何针对不同页⾯设置不同的 title 和 deion 来提升 SEO 效果,这时候,我们其实可以⽤ react-helmet 这样的⼯具帮我们达成⽬标,这个⼯具对客户端和服务器端渲染的效果都很棒,值得推荐。还有⼀些诸如⼯程⽬录的设计,404,301 重定向情况的处理等等,不过这些问题,我们只需要在实践中遇到的时候逐个攻破就可以了。

发布者:admin,转转请注明出处:http://www.yc00.com/news/1687987718a64204.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信