listen 443 ssl http2;
多路复用代替原有的序列以及阻塞机制,使得多个资源可以在一个连接中并行下载,不受浏览器同一域名资源请求限制,提升整站的资源加载速度。
(4)动态字体压缩
字体文件大小普遍在2M左右,H5活动页面字体量有限,但仅仅为少量特殊文字全量引入字体文件,页面性能损耗非常大。与此同时,由于营销活动的复杂性与多样性,单纯的图片字体很难满足多变的运营需求。
寻找满足字体多样性的同时,保证字体大小,是平台需攻克的技术难点,最终,我们探索出一套适用平台的动态字体压缩方案。
字体压缩,也可以被称为字体子集化,可以理解为通过特定方式将中英文字从大字体文件中剥离,组合成小字体文件供页面使用。
概念看上去有点抽象,我们先直观感受下压缩前后效果:
接下来会重点讲述悟空基于业务场景的字体压缩方案,压缩字体的核心诉求是:可压缩字体文件,可动态更换文本内容进行压缩。
基于悟空微组件动态打包上线方式,我们选择使用 fontmin 来完成动态压缩字体。
动态压缩字体分为以下几个步骤:
**第一步,**读取特定配置文件中的 id,预先请求到对应页面接口数据,进行数据归集处理。部分代码示例:
const request = require(‘request’)
request(url, (error, response, data) => {
if (error) {
console.error(err);
return
}
const res = JSON.parse(data)
if (res.code === 0) {
//获取专题配置数据
const config = JSON.parse(URLDecode(res.data.config))
const pages = config.pages
let str = ‘’
const familyList = new Set()
pages.forEach(page => {
const items = page.items
items.forEach(item => {
//根据配置,拼接需加载字体的字符串和字体类型
if (item.pluginInfo.enName === ‘site-text’) {
str += item.pluginConfig.pureText
familyList.add(item.pluginConfig.typeFace)
}
})
});
//处理字体
handleFont(str, familyList)
}
});
(滑动可查看)
**第二步,**遍历字体类型列表 familyList,利用 fontmin 进行字体文件压缩。这一步要求我们预先将字体的本地文件放入编译脚手架中。在压缩的同时,需要通过webpack插件来生成对应的 css 文件:
字体动态压缩处理逻辑:
const compressFont = (fontText, fontName) => {
const srcPath = dist/${siteId}/font/${fontName}.ttf
;
const destPath = dist/${siteId}/compressFont
;
const fontmin = new Fontmin()
.src(srcPath) // 输入配置
.use(Fontmin.glyph({ // 字形提取
text: fontText // 动态注入文字
}))
.use(Fontmin.ttf2eot()) // eot转换
.use(Fontmin.ttf2woff()) // woff转换
.use(Fontmin.ttf2svg()) // svg转换
.use(Fontmin.css({
fontPath: /compressFont/
,
fontFamily: fontName,
}))
.dest(destPath); // 输出文件
fontmin.run(function (err, files, stream) {
if (err) {
console.error(err);
return
}
// 读取生成后的对应的 css 文件内容并合成
const fontCss = fs.readFileSync(path.join(__dirname, ../dist/${siteId}/compressFont/${fontName}.css
)).toString()
fontStyleStr += fontCss
loadHtml(fontStyleStr)
})
}
const handleFont = (fontText, familyList) => {
familyList.forEach(name => {
compressFont(fontText, name)
})
}
(滑动可查看)
2、资源优化
(1)图片懒加载
图片懒加载是一种很好的优化网页或应用的方式,它能够在用户滚动页面时自动获取更多的数据,新获取的图片不会影响到页面呈现,同时视口外的图片有可能永远不需要被加载,能够极大的节约用户流量以及服务器资源。’
懒加载的一般形式表现为:
-
打开首页,滑动页面
-
懒加载图片展示默认图
-
默认图替换为真实图片
根据悟空现有的技术栈,我们选择vue-lazyload 去支撑位组件的图片来加载:
-
对 vue 的原生支持,平台扩展后所有组件都可使用
-
方便快捷的指令式开发,img 标签的 src 改为 v-lazy 就可以实现图片懒加载
-
功能符合预期,支持背景图片懒加载,支持图片 url 动态修改为 webp
悟空提供给组件开发者资源懒加载指令,用户无需感知具体的加载逻辑,通过悟空的内置能力即可实现专题图片懒加。具体用法如下:
<img
v-lazy=“‘img.400px.jpg’”
srcset=“img.400px.jpg 400w, img.800px.jpg 800w, img.1200px.jpg 1200w”
/>
<img
v-lazy=“imgUrl”
:srcset=“imgUrl’ + ‘?size=400 400w, ’ + imgUrl + ’ ?size=800 800w, ’ + imgUrl +’/1200.jpg 1200w’”
/>
(滑动可查看)
(2)图片压缩
在移动端环境下,图片加载一直是需要重点优化的关键项,所以才延伸出懒加载这种交互方案来提高用户体验。
当该方案优化到了落地后,我们下一步考虑如何在保证图片质量的前提下,尽量压缩图片体积,提升图片加载效率。
WebP 是 Google 推出的一种同时提供了有损压缩与无损压缩(可逆压缩)的图片文件格式。相比于其他相同大小不同格式的压缩图像,WebP 格式的图片拥有更小的体积以及更高的质量,所以它的优势十分明显。
WebP 是 Google 推出的一种同时提供了有损压缩与无损压缩(可逆压缩)的图片文件格式。相比于其他相同大小不同格式的压缩图像,WebP 格式的图片拥有更小的体积以及更高的质量,所以它的优势十分明显。
在使用 WebP 进行有损压缩后,我们大概可以将原本的图片大小压缩至原来的十分之一左右,而图片质量却没有大的损失。这确实是一个惊人的效率。
我们可以看下一组数据来看下 webp 有损压缩效果:
Webp 有损压缩(75%质量比)
await execFileSync(cwebp, [‘-q’, ‘75’, filePath, ‘-o’, webpPath]);
(滑动可查看)
原大小 | 压缩时间(ms) | 压缩后大小 |
999kb | 237 | 38kb |
999kb | 221 | 38kb |
999kb | 228 | 38kb |
999kb | 228 | 38kb |
999kb | 261 | 38kb |
在转换结束后,悟空会将原图片和转换后的 webp 图片都上传到 cdn 上,做一个备份的能力,实际业务场景可以根据需求去选择是否使用 Webp 图片。
下图展示 Webp 压缩前后效果,右侧展示压缩后图片,图片大小从215k减小至17k。
悟空在使用 Webp 压缩时,也遇到种种问题,如下:
-
为什么悟空选择 75% 的压缩质量?
-
什么特征的图片不适合Webp压缩?
-
部分图片压缩后资源变大
后续文章《悟空活动中台 - 基于Webp的图片高效加载方案》会详细叙述悟空如何从平台角度提供 Webp压缩方案。
(3)跨域避免 option 请求
悟空H5专题采用的是前后端分离方案,服务器域名和专题域名不一致,会受到浏览器同源策略影响。
我们发现数据主接口会发起两次,其中第一个请求为预检请求。
一般来说使用 application/json 的 post 请求是必然会带入 OPTION 请求,何为 OPTION 预检:
用于获取目的资源所支持的通信选项。客户端可以对特定的 URL 使用 OPTIONS 方法,也可以对整站(通过将 URL 设置为“*”)使用该方法。
在 CORS 中,可以使用 OPTIONS 方法发起一个预检请求,以检测实际请求是否可以被服务器所接受。预检请求报文中的 Access-Control-Request-Method 首部字段告知服务器实际请求所使用的 HTTP 方法;Access-Control-Request-Headers 首部字段告知服务器实际请求所携带的自定义首部字段。服务器基于从预检请求获得的信息来判断,是否接受接下来的实际请求。
有趣的是专题详情为 GET 接口,为何 GET 请求也会发起 option 预检?
这个原因得从简单请求和复杂请求说起,跨域请求分为简单和复杂两种:
简单请求:
请求方式为如下之一:
HEAD
GET
POST
HTTP 请求头只能包含如下信息:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type,但仅能是下列之一
application/x-www-form-urlencoded
multipart/form-data
text/plain
任何一个不满足上述要求的请求,即被认为是复杂请求。一个复杂请求不仅有包含通信内容的请求,同时也包含预检信息。
专题配置接口请求头中带有自定义 header,浏览器会认定为非简单请求,需要向服务器发出检查,判断该域名是否允许跨域。
经过分析发现,自定义 header 其实在此业务场景中非必传自带,发出预检请求至少会有 100ms 的耗时,无形中延长页面绘制时间。
最终解决方案:去除自定义header,修改为简单请求,避免该请求发出预检。
3、渲染执行优化
在网络层以及资源压缩优化落地后,接下来探索浏览器渲染执行优化点,涉及到浏览器,一定会联想到网页解析过程,下图清晰的展示静态资源如何通过浏览器最终显示:
当dom元素变化会导致浏览器重新执行渲染树生成、绘制,我们称之为重排重绘。
什么是重排?当 render tree 中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为重排(回流)。每个页面至少需要一次回流,就是在页面第一次加载的时候。
(1)避免重排
浏览器结构示意图:
可以看到浏览器有负责解析、渲染请求内容的渲染引擎,哪些动作会导致浏览器重排:
(1)增加或删除 DOM 节点;
(2)display:none(重排并重绘);
visibility:hidden(重绘);
(3)移动页面中的元素;
(4)改变元素尺寸(宽、高、内外边距、边框等);
(5)用户改变窗口大小,滚动页面等;
(6)页面初始渲染;
(7)改变元素内容(文本或图片等)。
offsetTop, offsetLeft,…
scrollTop, scrollLeft, …
clientTop, clientLeft, …
getComputedStyle() (currentStyle in IE)
(滑动可查看)
这些属性都需要实时回馈给用户的几何属性或者是布局属性,浏览器不得不立即执行渲染队列中的“待处理变化”,并随之触发重排返回正确的值。
document.body.style.minWidth = ‘12OOpx’
document.body.style.overflow = ‘hidden’
//获取某div的偏移量
document.querySelector(‘xxx’).offsetTop
(滑动可查看)
我们优化活动代码执行逻辑,将上述直接操作 dom 的操作修改为 class 样式操作,减少加载过程中重复的dom操作。
(2)善用 Vue 生命周期
善用 Vue 组件生命周期,在合适的 hook 去初始化数据,操作dom,能够大幅提升加载体验。
在mounted 阶段,浏览器已经完成 dom 与 css 规则树的 render,并完成 render tree布局,这时候再去发送数据请求,会拉长请求时间和渲染周期,所以建议在beforeCreate中执行,以此达到预渲染和请求的并行进行。
我们将活动初始化数据的动作放在 beforeCreate 阶段,并将对 dom 的操作和监听挂载在 mounted 中。
{
beforeCreate(){
fetch({
url: topicUrl,
params: {
//…
}
}).then(res=>{
//数据处理
//…
})
},
mounted() {
// global listener
window.addEventListener(‘xxx’);
// get dom element by refs
this.$refs.xxx
// get dom element use native api
document.querySelector
}
}
(滑动可查看)
对浏览器来说,整个渲染流程尚未开始或者说准备开始,对 vue 来说,实例尚未被初始化,data observer 和 event/watcher 也还未被调用,这个时候请求页面初始化数据时机是比较成熟的。
(3)减少白屏时间
相比 Native 页面,H5 页面体验问题主要是:打开一个 H5 页面需要做一系列处理,会有一段白屏时间,体验糟糕。
白屏时间是指浏览器从响应用户输入网址地址,到浏览器开始显示内容的时间。
本次专题优化,我们采用如下方式去减少白屏时间:
-
骨架屏,html直接渲染过渡效果
-
改造第三方 JS 引入顺序
-
使用 SplitChunksPlugin 拆分公共代码;
-
使用动态 import,切分页面代码,减小首屏 JS 体积
其中改造骨架的方式是一种成本低,效果非常卓越的方式,更进阶的方式有服务端直出等。由于悟空活动专题有快,灵的特点,配置改变需实时生效,所以前期我们权衡方案利弊,采用骨架,直接渲染过渡效果的方案。
页面加载html后直接显示加载效果,在底版本andriod手机中,webwiew初始化过程会有一个高度切换过程,加载后出现Native的titleBar,导致过渡效果会产生位置移动场景。
为了解决该问题,我们使用css3动画来实现过渡效果延迟出现,避免与webview初始化冲突。
animation: loading 1s linear 300ms infinite;
···
@keyframes loading{
from {
opacity: 1;
}
to {
opacity: 1;
}
}
(滑动可查看)
这一现象能侧面反映出,loading出现基本于webview初始化同期进行,速度很快。为了解决loaidng瞬移的问题,我们采用纯css3实现loading延迟出现,不与webview初始化冲突。
三、优化成果
1、同一专题优化前后数据对比
下述表格展示同一微组件和配置的活动在整体优化前后网站整体体验评分,评分来自PageSpeed Insights。
国内活动 | 优化前 | 优化后 |
首次绘制 | 2.8s | 1.3s |
速度指数 | 4s | 3.8s |
绘制耗时 | 12s | 2.3s |
综合得分(满分 100) | 44 | 90 |
海外活动 | 优化前 | 优化后 |
首次绘制 | 3.5s | 1.3s |
速度指数 | 5.6s | 3.3s |
绘制耗时 | 3.5s | 2.8s |
综合得分(满分 100) | 67 | 92 |
2、国内活动效果
相同配置专题:
3、海外活动效果
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(资料价值较高,非无偿)

最后
技术是没有终点的,也是学不完的,最重要的是活着、不秃。零基础入门的时候看书还是看视频,我觉得成年人,何必做选择题呢,两个都要。喜欢看书就看书,喜欢看视频就看视频。最重要的是在自学的过程中,一定不要眼高手低,要实战,把学到的技术投入到项目当中,解决问题,之后进一步锤炼自己的技术。
技术学到手后,就要开始准备面试了,找工作的时候一定要好好准备简历,毕竟简历是找工作的敲门砖,还有就是要多做面试题,复习巩固。有需要面试题资料的朋友点击这里即可获取!!!。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!*
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-DaCXqYD1-1711726291367)]
[外链图片转存中…(img-DZi15XsA-1711726291367)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
[外链图片转存中…(img-tGgD79F4-1711726291368)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(资料价值较高,非无偿)

最后
技术是没有终点的,也是学不完的,最重要的是活着、不秃。零基础入门的时候看书还是看视频,我觉得成年人,何必做选择题呢,两个都要。喜欢看书就看书,喜欢看视频就看视频。最重要的是在自学的过程中,一定不要眼高手低,要实战,把学到的技术投入到项目当中,解决问题,之后进一步锤炼自己的技术。
技术学到手后,就要开始准备面试了,找工作的时候一定要好好准备简历,毕竟简历是找工作的敲门砖,还有就是要多做面试题,复习巩固。有需要面试题资料的朋友点击这里即可获取!!!。
[外链图片转存中…(img-hPB5veyF-1711726291368)]