web应用无非是两台主机之间互相传输数据包
的一个过程; 如何减少传输过程的耗时就是网络方向优化的重点, 优化出发点从第一篇文章中说起
DNS解析
过程的优化当浏览器从第三方服务跨域请求资源
的时候,在浏览器发起请求之前,这个第三方的跨域域名需要被解析为一个IP地址,这个过程就是DNS解析;DNS缓存
可以用来减少这个过程的耗时,DNS解析可能会增加请求的延迟,对于那些需要请求许多第三方的资源的网站而言,DNS解析的耗时延迟可能会大大降低网页加载性能。
当站点引用跨域域上的资源时,都应在<head>元素中放置dns-prefetch提示,但是要记住一些注意事项。首先,dns-prefetch仅对跨域域上的DNS查找有效,因此请避免将其用于您当前访问的站点
<link rel="dns-prefetch" href="https://fonts.googleapis.com/">
由于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/">
这个前端方面好像能做的有限, 我们都知道 http协议 是基于 tcp的;
升级http协议版本可以考虑下, 比如把 http/1.0 -> http/1.1 -> http/2;
这个需要我们在应用服务器上配置(nginx, Apache等), 不做概述了, 另外还需要客户端和服务器都支持哦, 目前还没开发出稳定版本,好多只支持https,不过也不远了...
# 1.多路复用: 同一个tcp连接传输多个资源 这样可以突破统一域名下只允许有限个tcp同时连接, 这样http1.1所做的减少请求数优化就没有太大必要了 如多张小图合成一张大图(雪碧图),合并js和css文件 # 2.报文头压缩和二进制编码: 减少传输体积 http1 中第一次请求有完整的http报文头部,第二次请求的也是; http2 中第一次请求有完整的http报文头部,第二次请求只会携带 path 字段; 这样就大大减少了发送的量。这个的实现要求客户端和服务同时维护一个报文头表。 # 3.Server Push http2可以让服务先把其它很可能客户端会请求的资源(比如图片)先push发给你, 不用等到请求的时候再发送,这样可以提高页面整体的加载速度 但目前支持性不太好...emm...
总的来说, 在 c 端业务下不会太普及, 毕竟需要软件支持才行...
为了让数据包传输的更快, 我们可以从两个方面
入手: 请求的数据包大小(服务器), 请求数据包的频率(客户端)
请求文件对应的是我们项目完成后,打包所指的静态资源文件(会被部署到服务器), 文件越小, 传输的数据包也会相对较小, 讲道理也会更快到达客户端
目前我们都会使用打包工具了(比如webpack, rollup, glup 等), 如何使用工具来减小包的体积呢? 这边建议您去官网文档呢...当然这里列举一下常用的手段(webpack 的), 但是注意要插件版本更新哦
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 } }) ] }
// optimize-css-assets-webpack-plugin plugins: [ new OptimizeCSSAssetsPlugin({ assetNameRegExp: /\.css$/g, cssProcessor: require('cssnano'), }), ];
// 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, }, }), ];
1.代码不会被执行,不可到达,比如 if(false){// 这里边的代码} 2.代码执行的结果不会被用到 3.代码只会影响死变量(只写不读) 4.方法不能有副作用 // 原理相关: 以后在研究 利用 ES6 模块的特点: 只能作为模块顶层的语句出现 import 的模块名只能是字符串常量 import binding 是 immutable 的 代码擦除: uglify 阶段删除无用代码
分析出模块之间的依赖关系,尽可能的把打散的模块合并到一个函数中去,但前提是不能造成代码冗余
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') } ] })
有时候启用也会消耗服务器性能, 看情况使用吧
暂时先提这么些吧...后续想到了再加
因为同一域名下 tcp 连接数的限制导致过多的请求会排队阻塞, 所以我们需要尽量控制请求的数量和频率
这样这些资源无需从服务器获取, 但可能影响到渲染进程...
<!-- 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 服务提供的 URL 地址去访问; # 注意, cdn 缓存导致的新版本发布后不生效的问题 所以打包的时候常在文件后面加上 hash 值 然后在 HTML 文件中的资源引入地址也需要换成 CDN 服务提供的地址 /alicdn/xx12dsa311.js # 利用不同域名的 cdn 去存放资源, (tcp连接限制)
// 静态资源的导入 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