美文网首页
如何对 web 性能进行优化

如何对 web 性能进行优化

作者: sweetBoy_9126 | 来源:发表于2021-09-30 11:24 被阅读0次

    1. DNS 优化

    1.1. DNS 预解析

    以上面的代码为例,因为a.com 和b.com 是不同的域名,所以他会先对a.com 进行 dns 解析,拿到 ip 地址后去请求 1.js, 然后对 b.com 进行 dns 解析,拿到 ip 地址后去请求 2.js

    正常流程下 b.com 的解析肯定是要等到1.js下载并执行完成才开始;

    优化:我们可以先对a.com 和 b.com 同时进行2次的 DNS 查询,然后再依次的下载 1.js 和 2.js,这样就省掉了一个单独的 b.com 的 DNS 查询时间

    具体实现:
    1). 在 对应页面的 html 的 <head> 里写

    <!-- href 里的是对应的域名,所以无需具体到文件名 -->
    <link rel="dns-prefetch" href="http://a.com/">
    <link rel="dns-prefetch" href="http://b.com/">
    

    2). 在对应页面的 响应头里写

    Link: <https://a.com/>; rel=dns-prefetch
    

    2. TCP 连接优化

    2.1. 连接复用

    Connection:keep-alive

    正常情况下我们每发送一个请求,都会创建一个 TCP 连接,请求完成后响应然后会关闭 TCP 连接,所以如果有多个请求就会是
    开启 TCP 连接 -> 请求 -> 响应 -> 关闭 TCP 连接 -> 开启 TCP 连接

    优化:上面的 关闭 TCP 连接 -> 开启 TCP 连接 明显就是很多余的,那么我们可不可以不让它关闭直接再次请求,这样就不会每次先关闭再开启

    具体实现:在 http 的请求头和响应头里添加:Connection:keep-alive(通过添加 http 的字段可以实现 TCP连接的复用)

    问题拓展:我们对 TCP 连接进行了优化后我们现在的流程就是
    开启 TCP 连接 -> 请求1 -> 响应1 -> 请求2 -> 响应2
    那么响应1和请求2中间隔了多少秒才会被认为是需要复用的那
    所以我们需要设置一个时间我们两次的 http 请求间隔是多少秒,可以不关闭复用,超过这个时间就关闭,这时候我们就需要用到KeepAlive: timeout=5,max=1000
    这个意思就是如果你 5秒钟还不发起第二次请求,复用就会被关闭,max是最多请求 1000 次,请求头和响应头都可以设置KeepAlive,默认以响应头的为主

    **注意:如果你使用的协议的版本号 是HTTP/1.1 及以上那么 Connection:keep-alive 是自动加的

    2.2. 并行连接

    同时发送多个请求,每个请求都重开一个 TCP 连接
    并行连接有最大数量限制,一般是4-12个,这个限制跟域名有关

    具体实现:尽量将 css 和 js 拆成 2-3 个

    2.3. 管道化

    在并行的同时还复用之 TCP 连接
    问题:请求之间的顺序依赖,导致你这个并行没有办法达到最快的速度
    解决办法:协议升级为 HTTP/2.0

    3. HTTP/2 多路复用

    HTTP/1.1 基于字符串
    HTTP/2 基于帧(Frame),而帧是有9个字节+1个数据构成的

    上图中左侧是 HTTP/1.1 的请求,右侧是2的
    END_STREAM 前面如果是一个 + 表示'true',-是 false,所以+ END就表示结束了
    :method和:scheme和:path 叫做伪头,这三个伪头代表1.1的请求行

    多路复用

    只建立一个 TCP 链接的情况下,发送多个并行的请求


    4. 资源合并

    css雪碧图
    iconfont
    svg

    5. 资源内联

    小图片 -> data URL
    小 css 文件 -> <style>代码</style>
    小 js 文件 -> <scirpt>代码</script>

    6. 资源压缩

    原理:把响应传给浏览器之前,先把响应压缩成一个 gzip 包,浏览器拿到这个包后解压
    Nginx上面写个 gzip on,gzipTypes 可以指定对应的文件类型

    7. 资源精简

    HTML -> 删空格、删闭合
    CSS -> 删除未用的
    JS -> 改名、treeShaking
    SVG -> 删无用标签、属性
    图片 -> 减少体积

    8. 减少 cookie 体积

    cookie-free:使用新域名来避免使用本域名的cookie

    9. 使用 cdn

    • 优点:
    1. cookie-free
    2. 并行请求/多路复用
    3. 下载速度快
    • 缺点
    1. 可控性差
    2. 跨域

    cdn 会产生什么跨域问题?

    1. Canvas 虽然可以加载跨域图片,但是在调用 getImageData() toBlob() toDataURL() 时会产生报错,解决办法是启用 CORS 头,并给图片添加 crossorigin=anonymous 属性。详见 MDN
    2. window.addEventListener('error', ...) 无法捕获跨域 JS 的错误详情。解决办法有两个,一个是启用 CORS 头并给 script 标签添加 crossorigin=anonymous 属性,另一个比较开脑洞,是重写 addEventListener,详见《解决 "Script Error" 的另类思路》

    10. 代码优化

    10.1. 代码位置

    css引入写在head 里
    原因:
    1). css 不会阻塞 html 解析,尽早下载(如果 css 下载慢可能会出现白屏/闪烁)
    2). 防止外部 js 阻塞

    js 引入写在 body末尾
    原因:
    1). 可直接访问 dom,无须监听 dom ready
    2). 避免阻塞 HTML 解析

    10.2. js 动态导入

    普通 js写法

    const array = [1,2,3]
    import('lodash').then( _ => {
     const clone = _.cloneDeep(array)
    }) 
    

    vue 写法

    const router = new VueRouter({
     routes: [
     { path: '/home', component: () => import('./Home.vue') },
     { path: '/about, component: () => ({ 
     component: import('./About.vue'),
     loading: LoadingComponent,
     error: ErrorComponent,
     })},
     ]
    })
    

    react 写法

    import React, { Suspense, lazy } from 'react'
    import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
    const Home = lazy(() => import('./routes/Home'))
    const About = lazy(() => import('./routes/About'))
    const App = () => (
     <Router>
     <Suspense fallback={LoadingComponent}>
     <Switch>
     <Route exact path="/" component={Home}/>
     <Route path="/about" component={About}/>
     </Switch>
     </Suspense>
     </Router>
    )
    

    10.3. 图片懒加载

    懒加载就是一开始不加载,但需要用到的时候再加载。这听起来跟动态导入很像,不过懒加载一般指的是非 JS 资源,比如图片和样式
    常见的懒加载思路举例:
    1). 页面中有大量商品图片需要展示。假设代码为

    <img src="product.jsp" >
    

    2). 可以用一个 1k 大小的占位图片代替所有商品图片。代码改为

    <img src="placeholder.png" data-src="product.jpg">
    

    3). 在某个时刻(如页面加载的一秒钟后、用户滚动页面且快要看到下一页的产品时)使用 JS 去 加载商品图片,替换掉占位图片。

    10.4. 预加载

    懒加载导致一些资源的加载被推迟,影响了用户体验。所以我们需要提前对用户即将访问的资源进行加载

    10.5. css 优化

    1). 使用 uncss 删掉无用的 CSS
    2). 使用更高效的选择器
    3). 减少重排(reflow)。在比较多种样式修改方案时,尽量选择不会引起重排的方案。比如在做动画时,修改 transform 永
    远比修改 left、top、bottom、right 更好,因为 transform 不会引起重排。
    4). 不要使用 @import url.css; 因为被加载的 CSS 不能与当前文件并行下载。

    10.6. js 优化

    • 尽量不用全局变量,因为全局变量太多会使变量查找变慢。
    • 尽量少操作 DOM,可以使用 Fragment 一次性插入多个 DOM 节点。
    • 不要往页面中插入大量的 HTML,一定会卡。
    • 尽量少触发重排,可以使用节流和防抖来降低重排频率。
    • 尽量少用闭包,减少内存占用,避免内存泄漏(只有 IE 有内存泄露问题)。

    11. 缓存

    11.1. DNS 缓存

    当我们访问一个网站,会先通过浏览器去问 windows,windows 会去问电信,电信知道 ip 就会告诉 windows,windows 就会把这个 ip 缓存下来,一般是一天,然后告诉浏览器,浏览器也会把这个 ip 缓存下来

    11.2. HTTP 缓存

    Cache-Control
    public: 公开内容 (指定中间设备能不能对它进行缓存)
    max-age=3600 缓存时间
    must-revalidate 必须重新校验(缓存结束后的处理)/内容协商/弱缓存

    11.2.1. 内容协商

    协商的是缓存过期后还能不能重用
    具体流程:在第一次请求的时候拿到 服务器给的Etag(文件 md5 后的一个字符串),下一次请求的时候在请求头设置一个If-None-Match: xxx(上面Etag的值),等文件的缓存到期了,我们就把这个ETag发给服务器,服务器如果发现Etag没变就返回给浏览器一个 304 和空的响应,如果发现 ETag 变了,就返回一个 200 和新的文件内容

    11.3. 禁用缓存

    11.3.1. 服务器发起

    在有些情况下即使我们不设置Cache-Control 浏览器也会缓存
    比如:
    1). get 请求得到的响应一般会被缓存
    2). 状态码是 200 203(非权威信息) 206(部分内容) 300(多选) 301(永久重定向) 410(已迁移) 都会被缓存

    解决方法:
    在响应头里设置 Cache-Control: max-age=0,must-revalidate
    // 等价于上面的写法
    Cache-Control: no-cache 不缓存可以协商

    Cache-Control: no-store 不缓存不协商

    11.3.2. 浏览器发起

    1). 在请求的url后面加一个随机数
    比如: a.js?11111
    2). 请求的时候请求头设置 'Cache-Control', 'no-cache, no-store, max-age=0'

    相关文章

      网友评论

          本文标题:如何对 web 性能进行优化

          本文链接:https://www.haomeiwen.com/subject/nfcjnltx.html