重定向→拉取缓存→DNS查询→建立TCP链接→发起请求→接收响应→处理HTML元素→元素加载完成。
(1)设置浏览器缓存
etag on; //开启etag验证
expires 7d; //设置缓存过期时间为7天
4. 为我们的静态资源添加md5 hash后缀,避免资源更新而引起的前后端文件无法同步的问题。
(2)资源打包压缩
浏览器缓存工作,只有在用户第二次访问我们的页面才能起到效果,如果要在用户首次打开页面就实现优良的性能,必须对资源进行优化。
优化措施:
对上线文件进行自动化打包编译时,通常都需要打包工具:
webpack,Gulp和Grunt、Parcel
①JS压缩
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true // set to true if you want JS source maps
}),
...Plugins
]
}
②HTML压缩:
new HtmlWebpackPlugin({
template: __dirname + '/views/index.html', // new 一个这个插件的实例,并传入相关的参数
filename: '../index.html',
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
chunksSortMode: 'dependency'
})
③提取公共资源
splitChunks: {
cacheGroups: {
vendor: { // 抽离第三方插件
test: /node_modules/, // 指定是node_modules下的第三方包
chunks: 'initial',
name: 'common/vendor', // 打包后的文件名,任意命名
priority: 10 // 设置优先级,防止和自定义的公共代码提取时被覆盖,不进行打包
},
utils: { // 抽离自定义公共代码
test: /\.js$/,
chunks: 'initial',
name: 'common/utils',
minSize: 0 // 只要超出0字节就生成一个新包
}
}
}
④提取css并压缩:
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module: {
rules: [..., {
test: /\.css$/,
exclude: /node_modules/,
use: [
_mode === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader, {
loader: 'css-loader',
options: {
importLoaders: 1
}
}, {
loader: 'postcss-loader',
options: {
ident: 'postcss'
}
}
]
}]
}
⑤将webpack开发环境修改为生产环境:
上线时不需要这部分内容,通过配置剔除:
devtool: 'false'
⑥在服务器上开启Gzip传输压缩,它能将我们的文本类文件体积压缩至原先的四分之一
gzip on;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php application/vnd.ms-fontobject font/ttf font/opentype font/x-woff image/svg+xml;
不要对图片文件进行Gzip压缩!(gzip_types 把图片的相关项去掉)
(3)图片资源优化
资源打包压缩,只是停留在了代码层面,而在我们实际开发中,真正占用了大量网络传输资源的,并不是这些文件,而是图片
①不要在HTML里缩放图像
错误做法: 一个200✖200的图片容器内直接使用一张400✖400的图片
缺点:一张200KB的图片和2M的图片的传输时间会是200m和12s的差距
②使用雪碧图(CSS Sprite)
可以使用插件webpack-spritesmith 插件
缺点:必须知道位置,维护不方便
③使用字体图标(iconfont)
常用: icomoon 和 阿里图标 两个网站
icomoon 和 阿里图标 这个网站也为我们提供了将SVG图片自动转化成CSS样式的功能,然后进行引入~
④使用WebP
WebP格式,是谷歌公司开发的一种旨在加快图片加载速度的图片格式。图片压缩体积大约只有JPEG的2/3,并能节省大量的服务器带宽资源和数据空间。
⑤使用网络传输性能检测工具——Page Speed
chrome还为我们准备好了一款监测网络传输性能的插件——Page Speed,测试网络传输性能了
对测试网站的性能瓶颈提出完整的建议,我们可以根据它的提示进行优化工作。
⑥使用CDN
Linux下使用命令$ traceroute targetIp 或者在Windows下使用批处理 > tracert targetIp,都可以定位用户与目标计算机之间经过的所有路由器,不言而喻,用户和服务器之间距离越远,经过的路由器越多,延迟也就越高。使用CDN的目的之一便是解决这一问题,当然不仅仅如此,CDN还可以分担IDC压力。
我们搭建不起来CDN的,不过我们可以使用各大企业提供的服务,诸如腾讯云等,阿里云,等等配置也十分简单。
①浏览器渲染
Chrome(现在使用的是Blink引擎)
Safari使用的Webkit引擎,
Firefox使用的Gecko引擎,指的就是渲染引擎。
而在渲染引擎内,还包括着我们的HTML解释器(渲染时用于构造DOM树)、CSS解释器(渲染时用于合成CSS规则)还有我们的JS解释器。
②DOM渲染层与GPU硬件加速
一个页面是有许多许多层级组成的,他们就像千层面那样,你能想象出这个页面实际的样子吗?
布局是由CPU处理的,而绘制则是由GPU完成的
③重排与重绘
重排(reflow):渲染层内的元素布局发生修改,都会导致页面重新排列,比如窗口的尺寸发生变化、删除或添加DOM元素,修改了影响元素盒子大小的CSS属性(诸如:width、height、padding)。
重绘(repaint):绘制,即渲染上色,所有对元素的视觉表现属性的修改,都会引发重绘。
重排是由CPU处理的,而重绘是由GPU处理
CPU的处理效率远不及GPU,并且重排一定会引发重绘,而重绘不一定会引发重排。
④优化策略
(1)CSS属性读写分离
减少重排和重排,就是不用JS去操作元素样式,这也是我最推荐的。
(2)通过切换class或者style.csstext属性去批量操作元素样式(或者 css module 等模块化CSS),vue在style中添加 scoped
(3)DOM元素离线更新
当对DOM进行相关操作时,例如innerHTML、appendChild等都可以使用Document Fragment对象进行离线操作,带元素“组装”完成后再一次插入页面,或者使用display:none 对元素隐藏,在元素“消失”后进行相关操作。
(4)将没用的元素设为不可见:visibility: hidden,这样可以减小重绘的压力,必要的时候再将元素显示。
(5)压缩DOM的深度
一个渲染层内不要有过深的子元素,少用DOM完成页面样式,多使用伪元素或者box-shadow取代
(6)图片在渲染前指定大小
因为img元素是内联元素,所以在加载图片后会改变宽高,严重的情况会导致整个页面重排,所以最好在渲染前就指定其大小,或者让其脱离文档流。
(7)动画元素采取硬件加速
常见错误写法:
while(true){console.log("1111");}
while(1){console.log("1111");}
① Node.js处理IO密集型请求
“高内聚低耦合”的思想,你也可以用模块化的思想去理解,前后解耦就相当与把一个项目分成了前端和后端两个大模块,中间通过接口联系起来,分别进行开发。
② pm2实现Node.js“多线程”
node一般都是单线程,但是可以通过pm2 实现多线程。
pm2能启动多个node.js服务,并且它能够自动控制负载均衡,会自动将用户的请求分发至压力小的服务进程上处理。
安装 && 使用:
$ npm i pm2 -g
$ pm2 start pm2.json
即可③ nginx搭建反向代理
所谓代理就是我们通常所说的中介,网站的反向代理就是指那台介于用户和我们真实服务器之间的服务器(说的我都拗口了),它的作用便是能够将用户的请求分配到压力较小的服务器上,其机制是轮询。
nginx模块被分为三大类:
handler、filter和upstream.而其中的upstream模块,负责完成完成网络数据的接收、处理和转发,也是我们需要在反向代理中用到的模块。
(1)upstream配置信息:
upstream关键字后紧跟的标识符是我们自定义的项目名称,通过一对花括号在其中增添我们的配置信息。
ip_hash 关键字
:控制用户再次访问时是否连接到前一次连接的服务器
server关键字
:我们真实服务器的地址,这里的内容肯定是需要我们去填写的,不然运维怎么知道你把项目放在那个服务器上了,也不知道你封装了一层node而得去监听3000端口。
(2)server配置信息
server是nginx的基本配置,我们需要通过server将我们定义的upstream应用到服务器上。
listen关键字
:服务器监听的端口
location关键字
:和我们之前在node层说到的路由是起同样的功能,这里是把用户的请求分配到对应的upstream上