前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >漫谈前端性能优化

漫谈前端性能优化

作者头像
一粒小麦
发布于 2019-08-22 11:38:36
发布于 2019-08-22 11:38:36
81900
代码可运行
举报
文章被收录于专栏:一Li小麦一Li小麦
运行总次数:0
代码可运行

漫谈前端性能优化

url加载到页面加载完成发送了什么?

这是一个互联网从业者时常必须关注的问题。

作为前端关注浏览器。这个阶段,就是性能可以优化的时间。

  • 输入url=>通过dns,把url解析为ip
  • 和ip建立tcp链接(tcp/ip协议),发送http请求
  • 服务端接收请求,进行业务处理
  • 浏览器收到html开始渲染
  • html to dom
  • 解析css 为 css-tree
  • 加载js
  • 执行js

前端性能优化有两个大方向:

  1. 少加载文件(图片,代码)
  2. 少执行代码

现代浏览器的工作方式:推荐阅读《How Browser Works》

https://www.cnblogs.com/zjstar12/archive/2012/01/12/2320408.html

dns

前端在这块能做的事情比较少,

打开淘宝的网页源码,会发现有些标签预先获取一些dns。

淘宝首页加载时,这些域名的dns结果已经拿回来了。

TCP/IP协议

推荐阅读:图解TCP/IP,图解http,http权威指南,

在软件层面来说,最底层就是ip协议。ip最主要做的就是寻址。不负责数据内容。

TCP负责数据的完整性和有序。一旦发生丢包等,立即补发。(慢)

UDP和TCP是一层的协议,只发数据,但不管别的。主要使用场景:语音,视频等。(dns也是用的)

http:每次建立连接之前都会触发三次握手。了解一下:

第一次握手(你在不?)

第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。

第二次握手(我在哟)

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(seq=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手(那我发数据了哟)

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

优化方向

解决文件:图片绝对是大头。

减少文件体积
  • js,css压缩
  • 图片
    • 雪碧图(相对没那么推荐了,更新麻烦)。
    • 色彩丰富的小图=>png。
    • 轮播图之类=>jpg
    • base64还是svg好?前者弱点明显,只支持小图,后者作为矢量图,不失真,但增加了请求,牺牲了计算量。不能一刀切。
    • webP很优秀。但是在ios会有兼容性问题。
  • gzip代码压缩:至少减少一半。(见公众号文章:优化两则)

HTTP 压缩就是以缩小体积为目的,对 HTTP 内容进行重新编码的过程 Gzip 压缩背后的原理,是在一个文本文件中找出一些重复出现的字符串、临时替换它们,从而使整个文件变小。 根据这个原理,文件中代码的重复率越高,那么压缩的效率就越高,使用 Gzip 的收益也就越大。反之亦然。基本上来说,Gzip都是服务器干的活,比如nginx

减少文件请求次数
  • 懒加载(后面有实例)
  • http缓存。
  • 减少用户和服务器的距离(cdn)

http缓存(面试重点)

http请求流程

更多详情请见本公众号文章《http网络编程》

  • 客户端发送请求
  • 浏览器获取index.js
  • 此时前后端有一个协商的协议 是get还是post 请求什么文件index.js http/1.1
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
协议头:值
协议头:值
  • 服务器给你发文件
expires过期

缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点。也就是说,Expires=max-age + 请求时间,需要和Last-modified结合使用。但在上面我们提到过,cache-control的优先级更高。Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。

这种方式有一个明显的缺点,由于失效时间是一个绝对时间,所以当客户端本地时间被修改以后,服务器与客户端时间偏差变大以后,就会导致缓存混乱。于是发展出了Cache-Control。

Cache-Control:通过相应头询问http有无过期。

Cache control 浏览器没有,服务器给你文件。它是一个相对时间,例如Cache-Control:3600,代表着资源的有效期是3600秒。由于是相对时间,并且都是与客户端时间比较,所以服务器与客户端时间偏差也不会导致问题。Cache-Control与Expires可以在服务端配置同时启用或者启用任意一个,同时启用的时候Cache-Control优先级高。

max-age 指定一个时间长度,在这个时间段内缓存是有效的,单位是s。例如设置 Cache-Control:max-age=31536000,也就是说缓存有效期为(31536000 / 24 / 60 * 60)天,第一次访问这个资源的时候,服务器端也返回了 Expires 字段,并且过期时间是一年后。在没有禁用缓存并且没有超过有效时间的情况下,再次访问这个资源就命中了缓存,不会向服务器请求资源而是直接从浏览器缓存中取。

强缓存(200)

过期时间没到:直接200。

实际上这里是没有发送请求(from cache)。

弱缓存(协商缓存,304)

若未命中强缓存(如果已经过期了),浏览器也不会马上加载。

浏览器会将请求发送至服务器。服务器根据http头信息中的Last-Modify/If-Modify-SinceEtag/If-None-Match来判断是否命中协商缓存。如果命中,则http返回码为304,浏览器从缓存中加载资源。

如果没有修改,则返回304

etarg 指纹

与Last-Modify/If-Modify-Since不同的是,Etag/If-None-Match返回的是一个校验码(ETag: entity tag)。ETag可以保证每一个资源是唯一的,资源变化都会导致ETag变化*。ETag值的变更则说明资源状态已经被修改。服务器根据浏览器上发送的If-None-Match值来判断是否命中缓存。

用户操作对缓存的影响

如果都不行,那只能重载了!

大公司怎么上线前端代码?

普通文件上线不久是替换文件么?如果这样,用户可能在时间段内无法请求内容。

怎么上线

解决方案:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<script src="xx.js?_v=1.01" />
<script src="xx.js?_v=文件的哈希值" />

webpack-fis可以计算哈希值。

上线顺序

先上线模版html,导致加载的是旧的js会报错。

如果你的js哈希值变了。那么就会放弃旧的缓存,请求新的js资源。

因此:

  • html或者说模板,用不缓存。
  • js长期缓存。

性能优化实践

对于自己的代码,怎么优化?

我们打开一个过往项目,执行npm run build:

会发现gz压缩后的大小已经小了很多。但还是很大。如何去分析自己的项目?

分析工具:webpack-bundle-analyzer

vue ui可以看自己的项目。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
npm i webpack-bundle-analyzer -s

然后在webpack 配置里写:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const BundleAnalyzer=require('webpack-bundle-analyzer').BundleAnalyzerPlugin

module.export={

  //...

  plugins:[
    new BundleAnalyzer(),
    // ...
  ]
}

在开发环境中看http://localhost:8888,会发现:

Iview 的样式占了大头。那你就考虑是不是不要全局引入ivew.css了。

路由懒加载:

简单说:当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。

我们在vue-router里使用类似这样的方式2引入组件:

在react里面也是类似的。

服务端渲染(ssr)

传统的spa应用。首页白屏是非常常见的。对于seo来说也是非常不友好。根治这个问题,解决方案就是ssr。

一个同构应用,需要服务端(server和next两个入口)

vue的服务端渲染

本质就是在服务端把渲染的活给干了·

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const Vue = require('vue')
// 创建一个express应用
const server = require('express')()
// 提取出renderer实例
const renderer = require('vue-server-renderer').createRenderer()
server.get('*', (req, res) => {
  // 编写Vue实例(虚拟DOM节点)
  const app = new Vue({
    data: {
      url: req.url
        },
        // 编写模板HTML的内容
        template: `<div>访问的 URL 是: {{ url }}</div>` })
        // renderToString 是把Vue实例转化为真实DOM的关键方法
      renderer.renderToString(app, (err, html) => {
    if (err) {
      res.status(500).end('Internal Server Error')
      return
        }

        // 把渲染出来的真实DOM字符串插入HTML模板中
    res.end(`
      <!DOCTYPE html>
      <html lang="en">
        <head><title>Hello</title></head>
        <body>${html}</body>
      </html>
`) })
})
server.listen(8080)

关于nuxt.js我将在另外一篇文章中阐述。

react开启ssr

关键词:renderToString。属于react-dom的一个api

对于jsx语法,在服务端必须印图babel。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 注意这是服务端。
import express from 'express'
import React from 'react'
import { renderToString } from 'react-dom/server'
import App from './App'
const app = express()
// renderToString 是把虚拟DOM转化为真实DOM的关键方法
const RDom = renderToString(<App />)
// 编写HTML模板,插入转化后的真实DOM内容
const Page = `
            <html>
              <head>
                <title>test</title>
              </head>
              <body>
                <span>ssr </span>
                ${RDom}
              </body>
            </html>`
app.get('/index', function(req, res) {
  res.send(Page)
})
// 配置端口号
const server = app.listen(8000)

ssr理论必读。

雅虎军规

不一定都很合适。只能说在不同环境下有不同的配置。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
尽量减少 HTTP 请求个数——须权衡
使用 CDN(内容分发网络)
为文件头指定 Expires 或 Cache-Control ,使内容具有缓存性。避免空的 src 和 href
使用 gzip 压缩内容
把 CSS 放到顶部
把 JS 放到底部
避免使用 CSS 表达式
将 CSSJS 放到外部文件中
减少 DNS 查找次数
精简 CSSJS
避免跳转
剔除重复的 JSCSS
配置 ETags
使 AJAX 可缓存
尽早刷新输出缓冲
使用 GET 来完成 AJAX 请求
延迟加载
预加载
减少 DOM 元素个数
根据域名划分页面内容
尽量减少 iframe 的个数
避免 404
减少 Cookie 的大小
使用无 cookie 的域
性能监控

https://developer.mozilla.org/zh-CN/docs/Web/API/Performance

performance

直接在浏览器控制台输入

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
performance.getEntriesByType('navigation')

我们可以通过这个api来进行一个统计。

比如说,以下两个值之差就是dns寻找时间。

火焰图

重定向耗时:redirectEnd - redirectStart DNS查询耗时 :domainLookupEnd - domainLookupStart TCP链接耗时 :connectEnd - connectStart HTTP请求耗时 :responseEnd - responseStart 解析dom树耗时 : domComplete - domInteractive 白屏时间 :responseStart - navigationStart DOMready时间 :domContentLoadedEventEnd - navigationStart onload时间:loadEventEnd - navigationStart,也即是onload回调函数执行的时间。

lighthouse

lighthouse是一款由谷歌团队开发的一款开源的网站性能测评浏览器扩展程序。

目前测试项包括页面性能PWA可访问性(无障碍)最佳实践SEO。Lighthouse会对各个测试项的结果打分,并给出优化建议,这些打分标准和优化建议可以视为Google的网页最佳实践。

使用后可以看到网站性能。

节流和防抖

这是面试的重点。以班车为例子。

防抖

什么叫防抖?尝试手写一下。

设想你进行百度搜索,业务逻辑是输入每个文字(onkeyup),都弹出搜索建议。

但是这样每次调优都很很痛苦。我还没输入完成你就弹建议。不符合操作习惯。

所以防抖的核心思想是:频繁调用一个请求时,等待最后一个操作结束之后。才进行操作。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<input type="text" id="aaa">
<script>
    const aaa=document.querySelector('#aaa');
  aaa.addEventListener('keyup',(e)=>{
    // 假设这时就发送了请求。
      console.log(`你查找的是不是:${aaa.value}`)
    })
</script>

这段代码缺陷明显。我想输入111,还没输完就累计请求了3次。所以需要防抖一下。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        const aaa = document.querySelector('#aaa');

        // 防抖函数
        const debounce = function(fn, interval){
            if(this.timer){
                clearTimeout(this.timer);
            }
            this.timer = setTimeout(() => {
                fn();
            }, interval)
        }

        aaa.addEventListener('keyup', (e) => {
            debounce(()=>console.log(`你查找的是不是:${aaa.value}`),1000)
        });

最后只执行了一次。timer以闭包的形式存下来了。

节流

与防抖对应的就是节流,也就是说,我每隔一定的时间间隔,发车。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        // 节流
        const throttle=(fn,interval)=>{
            const lastTime=0;
            return function(...args){
                let now=new Date();
                if(now-lastTime>interval){
                    fn.apply(this,args);
                    lastTime=now;
                }
            }
        }

这样就省去了定时器。

防抖和节流在数据校验上很有用。没输完就校验是毫无意义的。

重绘和回流

回流:当你改变一个dom的几何尺寸。浏览器就会重新计算,导致其它标签外观变化。甚至触发蝴蝶效应。

这就是回流。

相反,你只是改了一个小div的颜色,其它属性没有变化,这就是重绘。

回流必定导致重绘,但重绘未必导致节流。

图片懒加载

懒加载通常会用data-url存放你想加载的图片。通过一定的条件触发加载。

长列表

给你1w条数据,怎么显示?

在一个长列表(虚拟列表)中,假设我有1w条,触发dom结构是非常痛苦的。

本质上就是和分页类似。

实际上只渲染可见的(前后2-3屏)。超过这个范围:触发新老节点替换渲染。

框架实现:react-virtualized 可以研究下源码实现。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 一Li小麦 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
前端性能优化
前端性能优化是提升用户体验、提高页面加载速度和响应速度的关键步骤。以下是一些核心优化策略和具体实现方法:
lpp182
2025/05/29
650
前端性能优化
你必须懂的前端性能优化
对于 DNS 解析和 TCP 连接两个步骤,我们前端可以做的努力非常有限。相比之下,HTTP 连接这一层面的优化才是我们网络优化的核心。
张炳
2019/08/02
7190
你必须懂的前端性能优化
前端性能优化总结
标记为async的脚本并不保证按照指定它们的先后顺序执行。对它来说脚本的加载和执行是紧紧挨着的,所以不管你声明的顺序如何,只要它加载完了就会立刻执行。
ConardLi
2019/09/08
1.2K0
【优化】356- 你必须懂的前端性能优化
对于 DNS 解析和 TCP 连接两个步骤,我们前端可以做的努力非常有限。相比之下,HTTP 连接这一层面的优化才是我们网络优化的核心。
pingan8787
2019/09/24
6420
【优化】356- 你必须懂的前端性能优化
前端性能优化归纳总结篇
关于前端性能优化的总结,随处都可以看到这方面的文章,而优化方法,也无外乎那些“固定”方面,当然,有些方面已经过时,所以,在这里,我自己也总结一遍吧,加深理解,也希望是一种不同的总结形式。
lyb-geek
2018/07/26
5590
Web 前端性能优化准则
“只有10%-20%的最终用户响应时间花在接收请求的HTML文档上,剩下的80%-90%时间花在HTML文档所引用的所有组件(图片,script,css,flash等等)进行的HTTP请求上”
书童小二
2018/09/03
1.1K0
Web 前端性能优化准则
前端性能优化原理与实践
在资源请求的过程中,涉及到网络请求的,包括:HTTP、TCP、DNS。其中TCP、DNS前端能做的工作非常有限,因此「优化HTTP」就成为了首要任务。
chuckQu
2022/08/19
1K0
拯救你的年底 KPI:前端性能优化
(给全栈前端精选加星标,提升前端技能) 原文地址:https://juejin.cn/post/6911472693405548557 作者:贩卖焦虑 前言 性能优化 ,每个工程师跑不掉的一个话题。
Nealyang
2021/01/13
1.1K0
拯救你的年底 KPI:前端性能优化
网站前端性能优化
继前面几篇文章后再来说说老生常谈的话题,怎么样提升前端性能。文中很多取材自网络及《High Performance Web Sites》,并根据自己工作中所接触到的知识整理而成。
全栈程序员站长
2022/07/15
2.2K0
页面性能优化的五种办法
大部分用户希望网页能在 2 秒之内就完成加载。事实上,加载时间每多 1 秒,你就会流失 7% 的用户。如果加载需要太长时间,他们就会放弃访问。
小生方勤
2019/06/03
1.2K0
前端面试必备技巧(二)重难点梳理
相比于第一篇 前端面试必备技巧,本篇文章更贴合今年的面试实际。第一篇比较全面,也比较基础,建议先看一遍上一篇再看本篇会更容易理解。
solocoder
2022/03/31
8830
前端面试必备技巧(二)重难点梳理
前端性能优化总结
做成一件事并不难,难的是做好一件事。前端性能优化也是同样的道理,性能是前端编码规范、网络层面、辅助工具等相互作用的结果,这是一个兼顾广度和深度的问题,优化好了可以加快首屏加载速度提高用户留存率,节省服务器资源降低成本等,也是区分初高级前端工程师的重要标准。
EchoROne
2022/08/15
8850
前端性能优化总结
前端性能优化
从用户访问资源到资源完整展现在用户面前的过程中,通过技术手段和优化策略,缩短每个步骤的处理时间从而提升整个资源的访问和呈现速度。
红目香薰
2022/11/29
6902
谈谈前端性能优化-面试版
当我们去面试的时候,很大概率会被面试官问这么一个问题:你有尝试过对项目做性能优化吗?或者你了解哪些性能优化的方法?听到这个问题的你可能是这样的:
loveX001
2022/10/11
1.3K0
桌面端前端性能优化策略
例如同一个域名 CDN 服务器上的 a.js,b.js,c.js 就可以按如下方式在一个请求中下载:
laixiangran
2018/07/25
2K0
【性能】688- 前端性能优化——从 10 多秒到 1.05 秒
关于 性能优化 是个大的面,这篇文章主要涉及到 前端 的几个点,如 前端性能优化 的流程、常见技术手段、工具等。
pingan8787
2020/08/21
1.3K0
【性能】688- 前端性能优化——从 10 多秒到 1.05 秒
如何全链路进行前端性能优化
通常来讲前端性能优化是指从用户开始访问我们的网站到整个页面完整的展现出来的过程中,通过各种优化策略和优化方法让页面加载的更快,让用户的操作响应更及时,给用户更好的使用体验。
桃翁
2021/12/01
1.2K0
如何全链路进行前端性能优化
高性能网站建设指南-前端性能优化(一)
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
奋飛
2019/08/15
7870
前端性能优化(PC版)
前端的性能优化是一个很宽泛的概念,最终目的都是为了提升用户体验,改善页面性能。面试的时候经常会遇到问谈谈性能优化的手段,这个我分几大部分来概述,具体细节需要自己再针对性的去搜索,只是提供一个索引(太多了写不过来+主要是懒得写)。这里PC端和移动端分开说了,业务场景不同,需要考虑各自的优化手段
红目香薰
2022/11/29
9220
【综合篇】Web前端性能优化原理问题
想要成为一名合格的Web前端工程师,Web前端性能优化是一个必须要掌握的知识,那么应该怎么进行Web前端性能优化呢?--达达前端
达达前端
2020/02/18
1.8K0
【综合篇】Web前端性能优化原理问题
相关推荐
前端性能优化
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验