2020-4-20 seo达人
性能优化(网络方向)
web应用无非是两台主机之间互相传输数据包的一个过程; 如何减少传输过程的耗时就是网络方向优化的重点, 优化出发点从第一篇文章中说起
DNS解析过程的优化
当浏览器从第三方服务跨域请求资源的时候,在浏览器发起请求之前,这个第三方的跨域域名需要被解析为一个IP地址,这个过程就是DNS解析;
DNS缓存可以用来减少这个过程的耗时,DNS解析可能会增加请求的延迟,对于那些需要请求许多第三方的资源的网站而言,DNS解析的耗时延迟可能会大大降低网页加载性能。
dns-prefetch
当站点引用跨域域上的资源时,都应在<head>元素中放置dns-prefetch提示,但是要记住一些注意事项。首先,dns-prefetch仅对跨域域上的DNS查找有效,因此请避免将其用于您当前访问的站点
<link rel="dns-prefetch" href="https://fonts.googleapis.com/">
preconnect
由于dns-prefetch仅执行DNS查找,但preconnect会建立与服务器的连接。如果站点是通过HTTPS服务的,则此过程包括DNS解析,建立TCP连接以及执行TLS握手。将两者结合起来可提供机会,进一步减少跨源请求的感知延迟
<!-- 注意顺序, precontent和dns-prefetch的兼容性 -->
<link rel="preconnect" href="https://fonts.googleapis.com/" crossorigin>
<link rel="dns-prefetch" href="https://fonts.googleapis.com/">
TCP传输阶段优化
这个前端方面好像能做的有限, 我们都知道 http协议 是基于 tcp的;
升级http协议版本可以考虑下, 比如把 http/1.0 -> http/1.1 -> http/2;
这个需要我们在应用服务器上配置(nginx, Apache等), 不做概述了, 另外还需要客户端和服务器都支持哦, 目前还没开发出稳定版本,好多只支持https,不过也不远了...
http2 的优势
# 1.多路复用: 同一个tcp连接传输多个资源
这样可以突破统一域名下只允许有限个tcp同时连接,
这样http1.1所做的减少请求数优化就没有太大必要了
如多张小图合成一张大图(雪碧图),合并js和css文件
# 2.报文头压缩和二进制编码: 减少传输体积
http1 中第一次请求有完整的http报文头部,第二次请求的也是;
http2 中第一次请求有完整的http报文头部,第二次请求只会携带 path 字段;
这样就大大减少了发送的量。这个的实现要求客户端和服务同时维护一个报文头表。
# 3.Server Push
http2可以让服务先把其它很可能客户端会请求的资源(比如图片)先push发给你,
不用等到请求的时候再发送,这样可以提高页面整体的加载速度
但目前支持性不太好...emm...
总的来说, 在 c 端业务下不会太普及, 毕竟需要软件支持才行...
http 请求响应阶段优化
为了让数据包传输的更快, 我们可以从两个方面入手: 请求的数据包大小(服务器), 请求数据包的频率(客户端)
减少请求文件的大小
请求文件对应的是我们项目完成后,打包所指的静态资源文件(会被部署到服务器), 文件越小, 传输的数据包也会相对较小, 讲道理也会更快到达客户端
how to reduce a package size?
目前我们都会使用打包工具了(比如webpack, rollup, glup 等), 如何使用工具来减小包的体积呢? 这边建议您去官网文档呢...当然这里列举一下常用的手段(webpack 的), 但是注意要插件版本更新哦
JS文件压缩
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
plugins: [
new UglifyJsPlugin({
// 允许并发
parallel: true,
// 开启缓存
cache: true,
compress: {
// 删除所有的console语句
drop_console: true,
// 把使用多次的静态值自动定义为变量
reduce_vars: true,
},
output: {
// 不保留注释
comment: false,
// 使输出的代码尽可能紧凑
beautify: false
}
})
]
}
CSS 文件压缩
// optimize-css-assets-webpack-plugin
plugins: [
new OptimizeCSSAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano'),
}),
];
html 文件压缩
// html-webpack-plugin
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src/index.html'),
filename: 'index.html',
chunks: ['index'],
inject: true,
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false,
},
}),
];
source map 文件关闭
tree shaking
1.代码不会被执行,不可到达,比如 if(false){// 这里边的代码}
2.代码执行的结果不会被用到
3.代码只会影响死变量(只写不读)
4.方法不能有副作用
// 原理相关: 以后在研究
利用 ES6 模块的特点:
只能作为模块顶层的语句出现
import 的模块名只能是字符串常量
import binding 是 immutable 的
代码擦除: uglify 阶段删除无用代码
scope hoisting(作用域提升)
分析出模块之间的依赖关系,尽可能的把打散的模块合并到一个函数中去,但前提是不能造成代码冗余
const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
module.exports = {
resolve: {
// 针对 Npm 中的第三方模块优先采用 jsnext:main 中指向的 ES6 模块化语法的文件
mainFields: ['jsnext:main', 'browser', 'main']
},
plugins: [
// 开启 Scope Hoisting
new ModuleConcatenationPlugin(),
],
};
项目中使用按需加载,懒加载(路由,组件级)
const router = new VueRouter({
routes: [
{ path: '/foo', component: () => import(/* webpackChunkName: "foo" */ './Foo.vue') }
{ path: '/bar', component: () => import(/* webpackChunkName: "bar" */ './Bar.vue') }
]
})
开启 gizp 压缩
有时候启用也会消耗服务器性能, 看情况使用吧
暂时先提这么些吧...后续想到了再加
减少请求频率
因为同一域名下 tcp 连接数的限制导致过多的请求会排队阻塞, 所以我们需要尽量控制请求的数量和频率
常见措施
将静态资源的内联到HTML中
这样这些资源无需从服务器获取, 但可能影响到渲染进程...
<!-- 1.小图片内联 base64 (url-loader) -->
<!-- 2.css内联 -->
<!-- 3.js内联 -->
<script>
${require('raw-loader!babel-loader!./node_modules/lib-flexible/flexible.js')}
</script>
利用各级缓存(下一篇存储方面介绍)
通常都是在服务端做相关配置, 但你要知道
我们可以利用http缓存(浏览器端)来减少和拦截二次请求, 当然一般都是在服务端设置的;
服务器端也可以设置缓存(redis等), 减少数据查询的时间同样可以缩短整个请求时间
利用本地存储
我们可以将常用不变的信息存在本地(cookie,storage API 等);
判断存在就不去请求相关的接口, 或者定期去请求也是可以的
花钱买 CDN 加速
CDN 又叫内容分发网络,通过把资源部署到世界各地,用户在访问时按照就近原则从离用户最近的服务器获取资源,从而加速资源的获取速度。 CDN 其实是通过优化物理链路层传输过程中的网速有限、丢包等问题来提升网速的...
购买 cdn 服务器;
然后把网页的静态资源上传到 CDN 服务上去,
在请求这些静态资源的时候需要通过 CDN 服务提供的 URL 地址去访问;
# 注意, cdn 缓存导致的新版本发布后不生效的问题
所以打包的时候常在文件后面加上 hash 值
然后在 HTML 文件中的资源引入地址也需要换成 CDN 服务提供的地址
/alicdn/xx12dsa311.js
# 利用不同域名的 cdn 去存放资源, (tcp连接限制)
webpack 构建时添加 cdn
// 静态资源的导入 URL 需要变成指向 CDN 服务的绝对路径的 URL 而不是相对于 HTML 文件的 URL。
// 静态资源的文件名称需要带上有文件内容算出来的 Hash 值,以防止被缓存。
// 不同类型的资源放到不同域名的 CDN 服务上去,以防止资源的并行加载被阻塞。
module.exports = {
// 省略 entry 配置...
output: {
// 给输出的 JavaScript 文件名称加上 Hash 值
filename: '[name]_[chunkhash:8].js',
path: path.resolve(__dirname, './dist'),
// 指定存放 JavaScript 文件的 CDN 目录 URL
publicPath: '//js.cdn.com/id/',
},
module: {
rules: [
{
// 增加对 CSS 文件的支持
test: /\.css$/,
// 提取出 Chunk 中的 CSS 代码到单独的文件中
use: ExtractTextPlugin.extract({
// 压缩 CSS 代码
use: ['css-loader?minimize'],
// 指定存放 CSS 中导入的资源(例如图片)的 CDN 目录 URL
publicPath: '//img.cdn.com/id/'
}),
},
{
// 增加对 PNG 文件的支持
test: /\.png$/,
// 给输出的 PNG 文件名称加上 Hash 值
use: ['file-loader?name=[name]_[hash:8].[ext]'],
},
// 省略其它 Loader 配置...
]
},
plugins: [
// 使用 WebPlugin 自动生成 HTML
new WebPlugin({
// HTML 模版文件所在的文件路径
template: './template.html',
// 输出的 HTML 的文件名称
filename: 'index.html',
// 指定存放 CSS 文件的 CDN 目录 URL
stylePublicPath: '//css.cdn.com/id/',
}),
new ExtractTextPlugin({
// 给输出的 CSS 文件名称加上 Hash 值
filename: `[name]_[contenthash:8].css`,
}),
// 省略代码压缩插件配置...
],
};
/*
以上代码中最核心的部分是通过 publicPath 参数设置存放静态资源的 CDN 目录 URL,
为了让不同类型的资源输出到不同的 CDN,需要分别在:
output.publicPath 中设置 JavaScript 的地址。
css-loader.publicPath 中设置被 CSS 导入的资源的的地址。
WebPlugin.stylePublicPath 中设置 CSS 文件的地址。
设置好 publicPath 后,WebPlugin 在生成 HTML 文件和 css-loader 转换 CSS 代码时,会考虑到配置中的 publicPath,用对应的线上地址替换原来的相对地址。
*/
参考
DNS MDN]
webpack 文档
深入浅出 Webpack
Scope Hoisting