能让你纵享丝滑的SSR技术,转转这样实践

大家好,我是若川(点这里加我微信 ruochuan12,长期交流学习)。今天推荐这篇图文并茂的SSR技术文章。这是江西前端群里一个小伙伴的文章。群里小伙伴很多都在知名大厂,但他们都很低调。

点击下方卡片关注我、加个星标,或者查看源码等系列文章。学习源码整体架构系列、年度总结、JS基础系列


SSR最佳实践

秒开率对于用户的留存率有直接的影响,数据表明, 网页加载时间过长会直接导致用户流失.转转集团作为一家电商公司, 对于H5页面的秒开率有着更加严格的需求, 在主要的卖场侧页面(手机频道页、3c频道页、活动页)等重要流量入口我们都采用了SSR(服务端渲染)技术来构建页面,今天就带大家了解一下我们摸索出来的一些最佳实践.

网页的前世今生

在早期的web应用中,实际上我们都是用的服务端渲染技术, 像jsp、asp、php等各种后台模板生成的页面,前端都是拿到整张页面,不用自己去拼接DOM.后来随着前后端分离开发模式,衍生出了最主要的两种渲染方式CSR以及SSR.

  • CSR : 客户端渲染,整个渲染流程是:  浏览器请求url --> 服务器返回index.html(空body、白屏) --> 再次请求bundle.js、路由分析 --> 浏览器渲染bundle.js体积越大, 就会导致白屏的时间越长,给用户的体验就越差(当然,这可以借助打包构建工具来优化这部分)

    交互流程图如下

图1-1客户端渲染流程图
  • SSR : 服务端渲染,  服务端渲染分为两个步骤:

  • 阶段一:  浏览器请求url --> 服务器路由分析、执行渲染 --> 服务器返回index.html(实时渲染的内容,字符串) --> 浏览器渲染  (此时是一个静态页面, 不可交互, 依赖于服务端的能力, 这就是快的原因)

  • 阶段二:浏览器请求bundle.js --> 服务器返回bundle.js --> 浏览器路由分析、生成虚拟DOM --> 比较DOM变化、绑定事件 --> 二次渲染 (用户可交互)

我们来看看整个交互流程图 :

图 1-2 服务端渲染交互流程图

SSR构建逻辑

理解了两种渲染模式的异同,我们来看看SSR整个构建逻辑(主要以Vue-SSR为例)

我们以官网的图片为例:

图 2-1 SSR构建逻辑

从图中我们可以知道 :

在整个构建过程中, 我们有两个入口, 一个是server-entry.js, 执行server端的逻辑, 一个是client.js, 执行client端的逻辑, 然后通过会将webpack打包分成两个Bundle: 服务端bundle; 客户端bundle. Node.js会处理服务端bundle用于SSR, 客户端bundle会在用户请求时和已经由SSR渲染出的页面一起返回给用户, 然后在浏览器执行”注水”(hydrate), 接管Vue接下来的业务逻辑.

理解了整个构建逻辑,接下来我们来看看我们是怎么运用SSR来服务我们的项目的.

SSR构建项目的背景

卖场侧业务首页组成大同小异: 主要分首屏和第二屏, 首屏有多个模块组成, 第二屏是商品Feed流,便于读者理解, 我们抽象出了页面结构图:

图 2-2 页面结构图

(欢迎大家下载转转app体验)

而且这些页面都有一个共同的特点:

  • 只用于展示, 和用户的状态不强绑定(不需要用户登录)

  • 页面状态稳定,内容不会经常变更

  • 都是重要流量的第一个入口(首页)

由于对于秒开率有着极高的要求,又承载了主要流量入口,结合以上页面特点,所以我们使用了SSR来提升用户体验.

经过一系列的探索和探究, 我们最终使用Nuxt.js来作为我们的技术选型.

这里提下为啥使用Nuxt.js作为我们的技术选型, 主要原因有以下几点:

  1. 集团内部C端业务是以Vue技术栈为主,B端技术栈是以React为主, 所以不考虑React服务端渲染技术栈;

  2. Nuxt.js是开箱即用的服务端渲染框架,不用开发人员自己去搭建Vue+ Vue-server-renderer + vuex来集成服务端渲染框架, 接入成本比较低.

SSR运用的最佳实践

目前我们使用SSR实现的主要能力有:

  • 首屏使用服务端渲染,第二屏使用客户端渲染,首屏模块数据可调整,即优化了性能, 又丰富了页面配置.

  • 合理化使用缓存, 进一步提升用户体验.

  • 实现css注入,达到按需换肤的效果.

  • 使用ErrorBoundary拦截错误,使得组件错误不会影响整个页面白屏.

  • 按需加载第二屏数据,只有滑动到可见范围, 才加载第二屏数据

  • 针对大促场景, 结合服务端能力, 以及各种监控,docker扩容,保证页面稳定.

接下来就和大家探索其中几种能力的主要思路:

怎样实现首屏使用服务端渲染,第二屏使用客户端渲染

这种实现方式主要是结合asyncData在服务端异步获取数据,使用vue动态组件component的特性,来调整模块的渲染顺序; mounted生命钩子只会在客户端执行, 使用仅在客户端渲染组件的特性来实现的.

示例代码:

<template><!--服务端渲染,动态获取首屏模块并且加载对应模块的数据, 使用error-boundary来拦截错误--><template v-for="(e, i) in structureOrder"><error-boundary><component :info="activityState.structure[e]":is="Mutations.name2Component(e)"class="anchor":id="e":key="i" :name="e" v-if="activityState.structure[e] || e === 'bar' "/></error-boundary></template><!--客户端渲染--><client-only><!--滑动到可见范围加载对应的数据--><div :is="listComponent" :tab="labelFilter"/></client-only>
</template>

获取数据:

//服务端渲染数据
async asyncData({app, route, req}) {const initData = await app.$axios.$get(host, {params: {name: key, from, smark, keys: `structure,base,labelFilter,navigate,redPack,${elements}`}, headers})const {structureInfo, structureOrder, restStructure, anchors} = Mutations.initStructure(initData)return {structureInfo,restStructure,structureOrder, //动态返回对应模块的名称useVideo: Mutations.checkUseVideo(req),theme,pageFrom: route.query.from,isPOP,anchors,...formInfo}
},
async mounted() {//获取客户端渲染的数据const res = await this.initData()
},

怎样使用ErrorBoundary捕获组件级别错误,避免整个页面白屏

关于ErrorBoundary这个捕获错误的组件,这个组件的主要功能是使得组件级的错误不会蔓延到页面级,不会造成整个页面的白屏,考虑到服务端渲染可能会发生偶发性错误,状态容易变的不可控, 所以使用这个能力还是很有必要的, 这个组件主要使用vue提供的 errorCaptured 来捕获组件级的错误, 想详细了解这个api的作用可以去看官方文档,具体的实现如下:

const errorBoundary = Vue => {Vue.component('ErrorBoundary', {data: () => ({ error: null }),errorCaptured(err, vm, info) {this.error = `${err.stack}\n\nfound in ${info} of component`SentryCapture(err, 1) //异常上报到sentryreturn false},render() {return (this.$slots.default || [null])[0] || null}})
}// 全局注册errorBoundary
Vue.use(errorBoundary)

怎样实现css注入,实现页面换肤

这个功能的主要作用是 : 可以根据配置json文件定制化活动页面的样式, 做到"千人千面" (一个会场的key可以配置一种样式, 但是底层代码是一套),使得元素多样化,在视觉上给用户体验带来很大提升.

我们先来看看效果示意图:

以上就是展示效果, 借住CSS注入, 我们可以根据不同的json文件来定制化页面的样式, 只需要维护一套代码, 简单高效.

实现逻辑也很简单,主要是运用了Nuxt.js框架提供的head方法:

head() {//this.baseInfo.additionStyle是从json文件拿到的样式//通过css权重, 可以实现样式覆盖return {style: [{cssText: this.baseInfo?.additionStyle || '', type: 'text/css'}],__dangerouslyDisableSanitizers: ['style']  // 防止对一些选择器的特殊字符进行转义}},

不仅如此, 还可以实现js注入, 感兴趣的小伙伴可以自己去了解,底层原理可以了解下 vue-meta 这个库

但是, 随着业务的不断迭代, 这种注入方式还是存在很多可优化的点:

  • 每个活动页运营同学都要维护一份json文件,里面包含冗长的css配置字段, 活动规则等等, 特别是css配置字段,就是一段冗长的css, 给运营和开发同学带来很大的不便;

  • 运营同学维护成本高,学习成本高,操作成本高;

  • 对于UI同学成本也大, 每次都需要UI同学来设计活动页面样式;

目前, 集团内部正在使用 魔方 一步一步去替代这种方式, 魔方 只需要运营同学拖拖拽拽, 就能生成一个活动页, 简单高效, 想要了解魔方的同学, 可以继续关注我们的公众号

怎样实现组件滑动到可见范围,才加载数据

其实这种优化页面的方法并不是说只适用于SSR, 其他非SSR页面也可以使用这种方式来优化;

看看我们的实现方式 :

function asyncComponent({componentFactory, loading = 'div', loadingData = 'loading', errorComponent, rootMargin = '0px',retry= 2}) {let resolveComponent;return () => ({component: new Promise(resolve => resolveComponent = resolve),loading: {mounted() {const observer = new InterpObserver(([entries]) => {if (!entries.isIntersecting) return;observer.unobserve(this.$el);let p = Promise.reject();for (let i = 0; i < retry; i++) {p = p.catch(componentFactory);}p.then(resolveComponent).catch(e => console.error(e));}, {root: null,rootMargin,threshold: [0]});observer.observe(this.$el);},render(h) {return h(loading, loadingData);},},error: errorComponent,delay: 200});
}export default {install: (Vue, option) => {Vue.prototype.$loadComponent = componentFactory => {return asyncComponent(Object.assign(option, {componentFactory}))}}
}

实现原理主要是使用vue高阶组件, 元素到达可见范围内, 延迟加载组件;

看看效果图:

我们可以看到,只有到底部商品Feed流出现在可视范围,才去请求对应的接口

针对大促场景怎样保证页面稳定

所谓大促场景,是指像 6.18, 双11,这种场景下, 面对大流量, 如何保证页面稳定? SSR是CPU密集型任务, 意味着很耗费服务器资源,集团目前主要采取的策略是:

  • 对接口进行压测, 模拟高并发场景下页面性能, 接口响应速度;

  • 集团内部实现了一套监控系统, 可以实时监控CPU,内存的消耗情况;

  • 需要有服务器扩容方案, 比如接入docker, 可以实现服务器实时扩容

怎样利用缓存

请大家移步集团一位前端大佬写的公众号文章: Nuxt实现的SSR页面性能优化的进一步探索与实践

最终,看看我们最终的实现效果:

可以看到, 首屏渲染时间在594ms, 秒开率在百分之87左右;

SSR的不足

ssr的使用过程并不是一帆风顺的, 在使用的过程中, 也总结几点不足之处:

  • 对于开发人员的要求更高, 要学习其他的额外知识,例如: Linux , node相关知识, 需要具备一定的后端思维;

  • 服务端渲染接口抓包不方便, 我们在客户端抓取不到服务端的接口请求, 不过对于使用Mac电脑开发的同学,可以使用 proxychains-ng 来抓取服务端请求的接口

  • 冗长的配置环境过程, 每次开发联调需要配置后端host

  • 对于服务器资源有要求,并发量越大, 资源消耗的越多

  • 服务端渲染可能会发生偶发性错误, 需要有一套降级方案

至于如何取舍, 看各位同学的项目需求,以及运用场景;

总结

SSR的使用有利有弊, 我们应该结合自己的业务特性去制定合适的方案, 它的优点就是快, 有利于SEO, 缺点也很明显, 比较耗费服务器资源, 对于亿级流量的超巨app来说, 理论上是不太合适的, 集团内部也有自己的一套方案来优化客户端渲染, 使得用户体验尽量向SSR靠齐.每一种技术的运用只有实践了才知道利弊,才能产生碰撞. 本文只是简单的带大家了解一条业务线上对SSR的运用, 所阐述的方面也只是冰山一角, 希望给广大开发者带来一定的启发, 前人栽树, 后人乘凉, 感谢转转FE前辈们留下的宝贵财富.

参考资料

nuxt官网:  https://www.baidu.com/link?url=xy0d8KPUgTmiVoGge6g-FgdeqjJSTjxdpT0tpxZzBG_&wd=&eqid=db50cacf00052e5e000000066081587d

Vue SSR指南: https://ssr.vuejs.org/zh/guide/


最近组建了一个江西人的前端交流群,如果你也是江西人可以加我微信 ruochuan12 拉你进群。


················· 若川出品 ·················

今日话题

写篇原创优质文章不容易,写了文章特别希望让更多人看到,写过文章的都懂。就像我现在每篇文章都带上源码系列链接,也是希望更多人看到。江西前端群里小伙伴写了这篇文章,我连忙联系开了白名单转载。公众号平台保护原创作者权益非常好,如果你看到一篇文章被转载多次,大概率说明这篇文章确实不错。欢迎分享、收藏、点赞、在看我的公众号文章~

一个愿景是帮助5年内前端人走向前列的公众号

可加我个人微信 ruochuan12,长期交流学习

推荐阅读

我在阿里招前端,我该怎么帮你?(现在还能加我进模拟面试群)

若川知乎问答:2年前端经验,做的项目没什么技术含量,怎么办?

点击方卡片关注我、加个星标,或者查看源码等系列文章。
学习源码整体架构系列、年度总结、JS基础系列

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/275959.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

魅族魅蓝mirror简单打开usb调试模式的步骤

经常我们使用安卓手机链接电脑的时候&#xff0c;或者使用的有些应用比如我们企业营销团队经常使用的应用引号精灵&#xff0c;以前使用的老版本就需要开启USB调试模式下使用&#xff0c;现经常新版本不需要了&#xff0c;如果手机没有开启USB调试模式&#xff0c;电脑则无办法…

hp-ux 单用户 启动_UX备忘单:搜索与浏览

hp-ux 单用户 启动重点 (Top highlight)When designing search results and interest sites, you have to keep in mind what ‘mode’ your user is in. Are they in ‘searching mode’ or ‘browsing mode’? This will help you determine how to design your platform to…

细数开源历史上的九个重大事件

开放源码&#xff08;开源&#xff09;的精神在于使用者可以使用、复制、散布、研究和改进软件。这可以追溯到20世纪60年代&#xff0c;至今已有半个世纪了。伯乐在线-职场博客的这篇文章将列举开源历史上的九大重要事件。虽然本文不是专门对开源产品&#xff0c;但还是说到了一…

有赞大数据平台安全建设实践

一、概述 在大数据平台建设初期&#xff0c;安全也许并不是被重点关注的一环。大数据平台的定位主要是服务数据开发人员&#xff0c;提高数据开发效率&#xff0c;提供便捷的开发流程&#xff0c;有效支持数仓建设。大数据平台的用户都是公司内部人员。数据本身的安全性已经由公…

请先设置tkk_理光MP2014扫描至文件夹的设置方法

理光旗下的2014系列入门级A3黑白复印机市场保有量较大&#xff0c;该系列机型加装M16网卡后可以方便的实现扫描至文件夹功能&#xff0c;经常有客户咨询该机型的扫描设置方法&#xff0c;下面我就以MP2014D为例来演示一下该机型的SMB扫描设置方法&#xff1a;首先是在电脑上建立…

听说现在都考这些React面试题

大家好&#xff0c;我是若川。最近刷脉脉看见圈里都在聊面试&#xff0c;吐槽最多的还是万年考点 React 和 Vue。不过关于两者的比较似乎有点针尖对麦芒的赶脚。确实&#xff0c;面试的偏重点往往映射公司对该框架的重视程度&#xff0c;但也不能一概而论&#xff0c;去学习或放…

荒岛余生为什么没有打开包裹_您会带到荒岛什么办公桌设置?

荒岛余生为什么没有打开包裹Throughout life, you experience a lot of desks and a lot of desk setups. Real or virtual, at the office or at home, temporal or permanent — just a way to call it, nothing is permanent— a big one with a great office view or a sma…

第五课 路由之初识路由

1.路由快速入门 1.1 概念 是指把数据从一个地方传送到另一个地方的行为和动作&#xff0c;而路由器&#xff0c;正是执行这种行为动作的机器。它的英文名称为Router&#xff0c;是一种连接多个网络或者网段的网络设备&#xff0c;它能将不同网络或者网段之间的数据信息进行“翻…

如何使用 React 和 React Hooks 创建一个天气应用

大家好&#xff0c;我是若川&#xff08;点这里加我微信 ruochuan12&#xff0c;长期交流学习&#xff09;。今天推荐一个练手的React项目&#xff0c;创建天气应用&#xff0c;相信很快能看完。昨天发送书掉粉18人&#xff0c;是我没想到的&#xff0c;送书一般是出版社按阅读…

拟态防御_纯素食汉堡的拟态

拟态防御If people are so against the idea of pigs and chickens being chopped up why would they want to buy fake bacon with realistic visual streaks of pork fat, or soy meat that tries to replicate the streaky texture of cooked chicken flesh? Surely these …

delphi 算术溢出解决方法_性能优化系列:JVM 内存划分总结与内存溢出异常详解分析...

前言那些使用过 C 或者 C 的读者一定会发现这两门语言的内存管理机制与 Java 的不同。在使用 C 或者 C 编程时&#xff0c;程序员需要手动的去管理和维护内存&#xff0c;就是说需要手动的清除那些不需要的对象&#xff0c;否则就会出现内存泄漏与内存溢出的问题。如果你使用 J…

微信小程序如何发送 http 请求

2019独角兽企业重金招聘Python工程师标准>>> 为什么要使用云函数发送 http 请求小程序云函数5 个可信域名不受限制需要备案无需备案在一些特殊情境, 比如域名没有备案或域名 5 个以上就需要使用云函数发送 HTTP 请求了. 如何使用云函数发送 HTTP 请求? 在云函数中能…

H5 页面列表缓存方案

大家好&#xff0c;我是若川&#xff08;点这里加我微信 ruochuan12&#xff0c;长期交流学习&#xff09;。今天给大家介绍一下关于h5页面的列表缓存方案。感谢屏幕前的你一直关注着我。点击下方卡片关注我、加个星标&#xff0c;或者查看源码等系列文章。学习源码整体架构系列…

不只是coding_不只是外表

不只是coding“We just need it to look more professional…”“我们只需要看起来更专业...” “We don’t have the graphic expertise you do…”“我们没有您所需要的图形专业知识……” “I just don’t know how to make it look good…”“我只是不知道如何使它看起来…

读取 wps_软件前世今生篇之WPS(求伯君1988年先于OFFICE研发出WPS)

软件前世今生篇之WPS今天给大家普及一下WPS这款办公软件&#xff0c;相信你会问wps有什么可普及的&#xff1f;我们都知道啊&#xff0c;不就是一款办公软件&#xff0c;而且还是抄袭office的&#xff0c;安装还挺简单的&#xff0c;而且还有一大堆广告&#xff0c;不过使用免费…

吴恩达机器学习笔记11-梯度下降法实践2-学习率

梯度下降算法收敛所需要的迭代次数根据模型的不同而不同&#xff0c;我们不能提前预知&#xff0c;我们可以绘制迭代次数和代价函数的图表来观测算法在何时趋于收敛。 也有一些自动测试是否收敛的方法&#xff0c;例如将代价函数的变化值与某个阀值&#xff08;例如0.001&#…

制作五彩纸屑转场动效_何时以及如何将五彩纸屑添加到产品UI

制作五彩纸屑转场动效As I am sure all designers have picked up on, confetti has become a popular method of (positive) feedback inside mobile and desktop apps. I will discuss the viable scenarios where you can implement confetti and will even provide some co…

【无套路送书】架构师是怎样炼成的?

大家好&#xff0c;我是若川。不知道这是今年第几次送书了&#xff0c;前三次分别是&#xff1a;第一次&#xff0c;第二次&#xff0c;第三次。本次《架构师的自我修炼》&#xff0c;非常珍贵&#xff0c;我争取到了2本送给大家&#xff0c;送书规则见文末。可以参与下&#x…

WinForm中使用Excel控件

&#xfeff;最近项目中要在WinForm中使用Excel控件&#xff0c;经过几天的研究&#xff0c;现在总结一下成果。 在WinForm中使用Excel控件主要有三种方法&#xff1a;WebBrowser、DSOFramer、OWC。下面分别描述一下如何使用。 一、WebBrowser /// -1、如何使用 WebBrowser 控件…

NASA公布“门户计划”,在月球轨道建立空间站进一步探索月球

门户是NASA研发一种小型的宇宙飞船的名字&#xff0c;该宇宙飞船将围绕月球轨道运行 成为宇航员临时住所和办公室。 日前&#xff0c;美国宇航局&#xff08;以下简称“NASA”&#xff09;公布了“门户计划”&#xff0c;该计划具体是指在月球轨道上建立空间站&#xff0c;以帮…