前端优化的手段

124 阅读6分钟

前言

前端作为用户交互的第一门户,前端的页面性能与用户的体验息息相关。通常体验越好,用户留存率会更高。那么我们有哪些手段来优化我们的页面呢?

css 优化

避免使用行内样式,尽量使用类选择器,其次才是 id 选择器

大量使用行内样式,导致我们的文档体积变大,影响加载速度。如果多个标签属性相同,会导致重复声明 css 样式,且打包体积更大。同时行内样式无法使 css 样式和 html 结构剥离。

在 css 样式比较多的情况,我们尽量使用外链 css,缩小打包体积

合并脚本和样式表,同时优先使用外链 css 文件引用,即 link,而非导入式 @import

导入式引用的问题:@import 在浏览网页时是先将 html 结构呈现出来,再把外部的 css 文件加载到网页中,对用户首屏体验感影响很大。而使用 link 引入 css 时,如果我们把 css 样式放在文档头部,客户端浏览你的网页时先将外部的 css 文件加载到网页,防止首次加载样式丢失。

引入资源利用 link 标签 rel 属性提供的一定预取能力

dns-prefetch 预解析。预先解析 href 指定的 dns 域名

preconnect 预连接。不仅预先解析 dns 还会把服务器握手完成

prefetch 预获取。资源被提前加载不执行和解析只是被缓存下来

prerender 预渲染。资源被提前加载并执行

dns-prefetch 和 preconnect 的存在可以让浏览器在解析文档的同时可以预先进行 DNS 解析或者预先建立一个链接,接下来加载 CDN 的其他资源时就可以更加快速

prefetch 和 prerender 可以告诉浏览器用户下个跳转的页面的地址,浏览器可以预加载这些页面资源到缓存或者预渲染好,前端用户体验优化

如何探测一个网页是否正被 prerender?答:打开 Chrome Task Manager 可以查看

注意脚本、静态资源的引入顺序,避免使用 iframe

css 样式放在文档头部,防止首次加载样式丢失。

JS 脚本、iframe 放在尾部,防止 <script><iframe> 标签在加载时,阻塞页面加载

避免使用或少用 iframe,iframe 加载会阻塞样式、dom 树的加载,如果使用 iframe,最好放在页面底部或者延迟加载插入

同时,在使用 iframe 时,会阻塞 onload 事件,影响页面加载。因此要将 onload 事件放在 onloadeddata 中。

局部 css,尽量使用css module

scoped 和 css module 的优劣

scoped:scoped 通过 webpack loaderd 配置 post-css, 转化后会给标签添加一个属性 data-a-hashString,打包体积比 css module 大,会影响首屏速度

css module: 无需产出额外的属性。使用 css module ,在 webpack 的 loader 配置中添加 modules 规则,即可在类名后自动生成 hash 后缀

modules:{

    localIdentName: "[local]_[hash:base64:5]"

}

其他手段

图片使用懒加载,列表节流、交互防抖

减少重绘重排,避免多次添加样式,添加重复样式

尽量使用 css3 动画,而不是用 JS 能力实现动画

元素批量添加事件时,尽量使用事件代理

图标不使用图片,使用体积更小的 iconfont、svg 等

减少打包体积

路由懒加载,依赖、组件按需引用,减少全局引用

component: resolve => (require(["@/components/HelloWorld"], resolve))

Or

const HelloWorld = ()=> import("@/components/HelloWorld")

压缩代码:减少资源大小可加快网页的显示速度,对代码进行压缩,并在服务器开启 gzip

vue

productionGzip改为true,开启Gzip压缩

nginx 

gzip  on;

gzip_types text/plain application/x-javascript application/javascript text/css application/xml 
text/javascript application/x-httpd-php image/jpeg image/gif image/png;

webpack

extract-text-webpack-plugin 用于将 css 从主应用程序中分离

optimize-css-assets-webpack-plugin 压缩提取出的 css,解决 extract-text-webpack-plugin 分离 CSS重复问题

commonsChunkPlugin 将公共模块拆出来,最终合成的文件能够在最开始的时候加载一次,便存到缓存中供后续使用

uglifyjs-webpack-plugin:webpack 默认使用它压缩js代码,需要说明的是可以在上面加上去除 `console.log` 的选项,也可以有效减少包体积

使用雪碧图

使用 map 标签来显示图片

网络请求

浏览器对单一域名有请求次数限制。同一域名的合并请求,减少 http 请求次数

http 2.0 分块编码传输

建立一个持久连接,将资源以分块编码方式传输,实现 chunk 并行化,response body 分块传输。前端收到 response body 后对相应的容器渲染,提高我们的 first paint 的时间

Response Headers

Connection: keep-alive

Transfer-Encoding: chunked

异步化预请求

预测用户操作,比如在用户 hoverclickfocus 等操作时,进行一个预测请求,并对预测结果缓存

引入 cdn,将静态资源分离

静态资源单独集群部署的好处

1、浏览器对单个域名有 http 并发请求上限,静态资源单独使用域名,在浏览器端可以增加并发连接数

2、静态资源单独域名,避免携带无用的业务 cookie,缩小请求体积,减小用户的带宽浪费,提高首屏速度

3、减小网站的流量压力,静态资源请求可能是网站的几十倍

4、接入 cdn,根据 ip 就近访问,提高加载速度

5、静态资源根据地区部署在不同地区的集群

本地缓存资源

通过添加 expires 头,设置 max-age,尽量长缓存,可以提高页面之后的加载速度

容器 + 内容分离

只需要请求我们内容渲染到容器中,而不是整个文档

预渲染

1、打包预渲染,打包时就把首页的部分静态的 html 加载在 index.html 中来提高首页加载速度

2、spa 单页面应用可以通过 webpack 中 plugin 配置,借助 prerender-spa-plugin 给指定路由生成静态页面,提高页面渲染的速度,也利于 seo 

new PrerenderSPAPlugin({ 
    staticDir: path.join(__dirname, 'dist'), 
    routes: ['/', '/home'], 
    renderer: new Renderer({ 
        headless: false, 
        renderAfterDocumentEvent: 'render-event' 
    })
})

3、服务端渲染后返回静态 html,可以使用 php 或者 node 渲染和 JS 脚本能力。前端分别请求静态模板、静态资源、脚本。再由前端渲染静态 html 模板,最后将脚本和静态资源结合