前端发展日新月异,如今已经到2021年,让我们看看有哪些被忽略的相对较新的技术可以运用到我们的项目中,打造极致体验,从此刻开始:
一、QUIC
基于 UDP 的低延时网络传输层协议,http3 将基于此协议制定
优势: 提升 15% 以上的访问速度,弱网络环境提升 20%以上
相比于 http2:
-
连接的延时低。
-
改进的拥塞控制。
-
没有队头阻塞的多路复用。
劣势: Firefox 和 Edge 不支持,NGINX 需要 1.7.0 及以上,而 1.7.0 还不稳定
部署:
方案 | 优势 | 劣势 | 可能性 | 使用基于 quic-go 的 caddy 处理 QUIC 请求https://caddyserver.com/docs | 能够支持 QUIC | 需要安装 caddy,需要运维支持 低 | 高 | 升级 NGINX,NGINX 原生支持 QUIC | 只需升级 NGINX | 需要 NGINX 的 1.7.0 及以上才支持,1.7.0 还不稳定,未进入 stable 阶段 | 低 |
---|
总结: QUIC 在网络传输层提高数据的传输速度。与硬件升级不相关,只需要软件的支持即可。
能够兼容不支持 QUIC 的设备。
设备支持情况:Chrome 从 29 开始支持,Safari 支持,Firefox 和 Edge 开发中。(参考:https://www.chromestatus.com/feature/5338403830759424)
最好是等待 NGINX 稳定便可实施。
二、可优化的 http 头信息
1. 数据压缩 Brotli
content-encoding: br
优势: Google 开发的 Brotli 压缩格式,它通过内置分析大量网页得出的字典,实现了更高的压缩比率,同时几乎不影响压缩 / 解压速度。
以下是摘取自 benchmark 的对比数据:
下图是针对京东首页启用 Brotli 压缩对比 Gzip 的压缩比的情况,在 5 级压缩以上,Brotli 明显好于 Gzip。(参考:https://tools.paulcalvano.com/compression.php) 以下是压缩速率对比,可以看到 Brotli 的同样的压缩率比 Gzip 要快。
劣势: 设备支持的情况一般,iOS11 以上才支持。NGINX 配置需要额外安装模块。
部署: NGINX 需要安装 nginx-plus-module-brotli 模块 (参考:https://docs.nginx.com/nginx/admin-guide/dynamic-modules/brotli/)
具体配置如下:
#Brotli Compression
brotli on;
brotli_comp_level 5;
brotli_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;
总结:
br 压缩比较适合于静态文件的传输,尤其是在弱网络的情况,传输的数据越少对网络情况的依赖越低。
NGINX 支持 brotli 的话,需要额外安装模块,可能需要运维支持。
2. 安全相关的头信息
strict-transport-security: max-age=31536000
通常简称为 HSTS 是一个安全功能,它告诉浏览器只能通过 HTTPS 访问当前资源,而不是 HTTP。
x-content-type-options: nosniff
有些资源的 Content-Type
是错的或者未定义。这时,某些浏览器会启用 MIME-sniffing
来猜测该资源的类型,解析内容并执行。但是这样有存在 XSS 攻击的风险。建议显示关闭。
x-frame-options: SAMEORIGIN
减少点击劫持,告诉浏览器哪些页面允许以 iframe 的形式嵌入。
- DENY:不允许被任何页面嵌入;
- SAMEORIGIN:不允许被本域以外的页面嵌入;
- ALLOW-FROM uri:不允许被指定的域名以外的页面嵌入(Chrome 现阶段不支持);
Content-Security-Policy: default-src 'self'
启用 CSP(内容安全协议),类似于开启网站内容加载白名单,目前浏览器已经全面支持。可以有效的防止 XSS 攻击以及一些 webview 的 js 注入等。
以下摘取一些限制类型:
# 限制各类资源的加载
script-src:外部脚本
style-src:样式表
img-src:图像
media-src:媒体文件(音频和视频)
font-src:字体文件
object-src:插件(比如 Flash)
child-src:框架
frame-ancestors:嵌入的外部资源(比如<frame>、<iframe>、<embed>和<applet>)
connect-src:HTTP 连接(通过 XHR、WebSockets、EventSource 等)
worker-src:worker 脚本
manifest-src:manifest 文件
# URL 限制
frame-ancestors:限制嵌入框架的网页
base-uri:限制<base#href>
form-action:限制<form#action>
同时,CSP 还支持注入行为的报告,可以用 report-uri。
report-uri http://test/
(参考: www.ruanyifeng.com/blog/2016/0…)
三、可优化性能的技术
1.requestIdleCallback & requestAnimationFrame
requestAnimationFrame
具体作用是在浏览器在完成一次渲染之后,立即执行里面的回调函数,即下一帧开始时执行。
首先是支持情况,不然一切都白说。这个 api 目前几乎所有浏览器都支持(IE10 以下除外),看下图:
requestIdleCallback
具体作用是在浏览器主线程完成任务以及渲染之后,如果这一帧还有空余时间,就会执行回调函数。
这个 api 目前浏览器支持的程度很一般,不过可以通过 polyfill 垫片模拟实现类似的效果。
优势:
requestAnimationFrame
可以用于在优先级高,但是又不需要立马执行,即可以在当前帧渲染完再去执行操作。
与 setTimeout 不同,setTimeout 在宏队列, 下一帧还不一定能够立马执行。
所以通常可以用在动画中,保证动画的频率与显示器的刷新频率保持一致。
requestIdleCallback
可用于 js 的拆分,把不需要立马执行(可以默默执行)的 js 放在这里执行。
也可以用于防抖或者节流中,用于代替 setTimeout,因为使用 setTimeout 并不一定能真的延后执行,setTimeout 只是在某段时间之后,把回调函数放入执行队列。但是这个时间并不是太好掌控。而 requestIdleCallback 就可以做到没执行就解除之前的绑定,再执行新的绑定。
这两个结合可以更好的控制 js 主线程执行,给用户更好的交互体验。
劣势:
依然是浏览器支持的问题,因为这两个方法都是浏览器内核用 C++实现的原生方法。polyfill 能做的只是尽可能的模拟。
如果不用考虑 requestAnimationFrame 的兼容性,requestIdleCallback 可以通过 requestAnimationFrame 获取浏览器这一帧的开始时间,requestIdleCallback 执行时判断这一帧是否还有剩余时间。
部署:
- 可以用 main-thread-scheduling 这个类库实现调度。
- 也可以模拟实现 requestIdleCallback 和 requestAnimationFrame 中的方法
- Vue3.0 将应用时间调度,来防止在大型应用中,递归更新 dom 时调用栈太深导致的主线程堵塞的问题
总结:
requestIdleCallback 和 requestAnimationFrame 调度的合理利用确实能带来更好的用户体验。
2.InsterSectionObserver
IntersectionObserver 提供了一种异步观察目标是否进入了设备的可视区域之内,而不需要频繁的计算来做这个判断。(参考:https://developer.mozilla.org/zh-CN/docs/Web/API/IntersectionObserver)
来看下目前它的支持情况,iOS12 目前已经支持,IE 全体阵亡。
优势:
主要应用于懒加载,我们通常使用监听 scroll 或者使用 setInterval 来判断,元素是否进入视图,其中 scroll 由于其特别大的计算量,会有性能问题,而 setInterval 由于其有间歇期,也会出现体验问题。
IntersectionObserver 由浏览器原生提供,浏览器内部也会进行一定的优化。
部署:
可以先判断浏览器支不支持 IntersectionObserver
,如果支持优先使用该方法,不支持的话继续应用 scroll 方案。
也可以借鉴 vue-layload
的懒加载实现方案。
vue-layload
它也提供两种模式,默认使用 scroll。但是如果我们指定用 IntersectionObserver
的话,它内部也会去判断当前环境支不支持,如果不支持也会回落到 scroll 模式。
总结:
IntersectionObserver
如果能应用到实践项目中,对于性能的提升应该也是有帮助的。
具体还有待测试。
3. GraphQL
不同于 RESTful 规范,GraphQL 使前端有能力直接使用类似查询语句的方式向后端精确地请求数据。
优势:
- 数据冗余和请求冗余,避免多次请求,减少带宽的占用
- 灵活而强类型的 schema,可以进行数据的校验,避免前端数据类型的判断
- 只需提供一个大而全的接口,类似于 fapi
劣势:
- 需要后端的支持
- 需要 Node 环境
- 每一个 field 都对数据库直接跑一个 query,会产生大量冗余 query,影响数据库性能
总结:
可行性低,目前 GraphQL 也并没有『火起来』。这里只是普及下有这么个玩意。
四、图片加载优化解决方案
图片加载的缓慢与否,直接关乎到用户的体验,图片越清晰,给用户带来的观感更好,但是占用的带宽资源更严重,所以如何在不影响图片质量的前提下快速地把图片分发给用户是一个需要深入探讨的问题。
1. Chrome 原生支持的懒加载
具体配置信息如下:
- auto 浏览器自行判断
- on 开启懒加载
- off 关闭懒加载
具体的效果如下:
CodePen Native lazy load
优势:
- 原生支持,不需要写复杂的 js 逻辑
- lazyload 还支持 iframe ,因此一些嵌入 iframe 的站点可以尝试使用
劣势:
- 试验属性,几乎没有浏览器支持,Chrome 需要在 flags 中打开
- UI 效果可能一般
2. LQIP 用户体验优化方案
LQIP
(Low Quality Image Placeholders 压缩图片优先呈现),其实就用一张超小成本的图片当做占位符,一般的占位符有留白、统一的一张图、纯色、模糊图像。
实现的过程如下:
- 优先给用户呈现一张高度压缩的图片(可能只有 1kb 左右的图片),可能是一个图片的 url,或者一个内嵌的 base64 图片,并带上 blur 效果。
- 加载小图的同时去请求大图
- 一旦大图加载完,于是区域便展示大图,而小图隐藏掉
- 所有的过程都是通过 transition 动画过渡
部署:
谷歌是如何使用图片预加载的?
谷歌在进行图片加载的时候会预先将背景渲染出一种固定的颜色,随后才显示完成加载的图片。他们使用的是图片中最主要的色彩,然后将其运用在背景上,从而给人一种快速加载的效果。至于是如何知道图片中的主要色彩是什么,我估计是搜索引擎结合算法得出来的。
vue-lazyload 提供的方法
filter 选项,可以在指令的 bind 阶段获取 listener 的 dom 节点,再次设置 loadding 的图片 通过属性选择器设置 css 动画
Vue.use(vueLazy, {
filter: {
progressive(listener, options) {
const isCDN = /qiniudn.com/;
if (isCDN.test(listener.src)) {
listener.el.setAttribute("lazy-progressive", "true");
listener.loading = listener.src + "?imageView2/1/w/10/h/10";
}
}
}
});
<img src="imgUrl" lazy="loading" />
<img src="imgUrl" lazy="loaded" />
<img src="imgUrl" lazy="error" />
以下是代码的实现效果:
CodePen Reproducing Medium loading image effect
总结:
体验最好的肯定是模糊图像的过渡,我看到知乎已经使用了这种体验技术。好处是提升用户体验,使用户在等待过程中能感受到图片加载的整个过程。但是加载的数据变多了,在 http2 多路复用的加持下,不用担心浏览器只允许 6 个同时的 tcp 链接的限制,影响能减到最低。
3.响应式图片解决方案
在设计响应式页面的时候,针对不同设备加载不同图片不仅能节约带宽,而且能有更好的显示效果。(参考:https://www.responsivebreakpoints.com/)
3.1 img 标签的 srcset 和 sizes 属性
<div style="width:50%;">
<img
style="width:100%;"
src="img/480.png"
srcset="img/480.png 480w, img/800.png 800w, img/1600.png 1600w"
sizes="(min-width: 800px) 800px, 50vw"
/>
</div>
srcset 指定图片的地址和对应的图片质量,sizes 用来设置图片的尺寸临界点,明确定义了图片在不同的 media conditions 下应该显示的尺寸。若不设置 sizes,其默认值为 sizes="100vw",vw(viewport width)是代表视口宽度的相对单位。以上示例表示在最小宽度是 800 像素时,即大于等于 800 像素时,显示 800 像素的图片,其他情况下就是以百分之百的视口宽度为参考显示图片。
总结:
用 vue-lazyload 本身也支持设置多个图片,然后通过设备的宽度来选择最优的图片显示。
3.2 picture 标签
浏览器会遍历<picture>
中的<source>
,直到找到一个<source>
满足当前环境,然后将该<source>
中的 srcset 设置到<img>
中。
<picture><source srcset="large.jpg" media="(min-width: 800px)">
<source srcset="medium.jpg" media="(min-width: 600px)">
<img srcset="small.jpg">
</picture>
优势:
可以给图片设置多组的 srcset,并且是通过媒体查询触发的改变,不会因为已经缓存了高质量大图而在屏幕变小的时候仍使用大图。
劣势:
- IE 全部阵亡
- 增加了复杂度,本来我一个图片只要写一个标签
- 很多情况下,不需要 srcset 就能解决问题,换屏幕大小的场景不多
总结:
其实这个规范从 Chrome38 就开始支持,但是很多情况下都是用 srcset 代替了,所以没有广泛应用开来。而且用 vue-lazyload 本身也支持设置多个图片,然后通过设备的宽度来选择最优的图片显示。
五、资源加载的优化
下图是百度(https://www.baidu.com/)页面的资源执行情况占比的报告,可以看出js以及css的未使用率都在50%以上,还是有优化空间的。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!