1、URL
- scheme://host.domain.port/path/filename
- scheme :传输协议,http/https/file/ftp
- host :定义域主机,http 默认的主机是www
- domain :域名,如:baidu/google/taobao
- path:定于服务器上的路径
- filename :文档/资源名称,如:.html/.css/.js
2、DNS解析
DNS协议通过域名解析查找IP地址,或逆向从IP地址反查域名。DNS就是一个网络服务商,我们的域名解析就是在DNS上的一条记录
1、DNS缓存
- 浏览器缓存:浏览器会按照一定频率记录DNS
- 操作系统缓存:如果浏览器话黁中找不到需要的DNS,就去操作系统中查找
- 路由器缓存:路由器也有DNS缓存
- ISP的DNS服务器:互联网服务提供商有专门的DNS服务器查询对应的域名
- 根服务器:.com
2、DNS优化
- DNS缓存:
- 浏览器缓存、操作系统缓存、路由器缓存、ISP缓存、根服务器缓存
- 系统缓存(mac: /etc/hosts)
- DNS负载均衡
- 根据每台机器的负载量,返回 合适的机器IP给用户
3、发起TCP请求
1、TCP传输服务
- 提供一种可靠的传输,这个过程面向连接的字节流服务。
2、三次握手
- 第一次:客户端发送syn包(Seq=x)到服务器,并进入SYN_SEND的状态,等待服务器确认
- 第二次:服务器收到syn包,必须确认客户端的 syn(ack= x+!),同时自己也发送一个syn包 (Seq=y),syn+ack 包,此时服务器进入 SYN_RECV状态
- 第三次:客户端收到服务器的syn+ack包,向服务器发送确认包 (ack=y+1),这个包发送完毕,客户端和服务器进入 ESTABLISHED状态,此时完成三次握手
3、四次挥手
- 客户端发送一个FIN,用来关闭客户端到服务器的数据传送 FIN=1,序列号 seq=u(+!),进入FIN-WAIT-1的状态(终止等待-1)
- 服务器收到FIN包后,发送一个ACK给对方并且带上自己的序列号sq,确认序列号为手打序号+1,服务器进入CLOSE-WAIT(关闭等待)状态。这个时候客户端已经没有数据要发送了,但是服务如果发送数据客户端依然要接受,这个状态要持续一段时间,即COLSE-WAIT状态的持续时间。
- 服务器发送一个FIN,用来关闭服务器到客户端的数据传送,也就是告诉客户端,数据发送完了。假定此时的序列号是seq=为,服务器进入LAST-ACK(最后确认)状态,等待客户端的确认。
- 主动关闭方(客户端)收到FIN后,发送一个ACK给服务端,确认序号是收到的序号+1,此时,客户端进入TIME-WAIT(时间等待)状态。服务器只要收到客户端发送的确认,立即进入CLOSE状态。客户端还需要等待2*MSL(最长报文寿命)后,才进入CLOSE状态。
4、发送HTTP
1、请求行
- method Request-URL HTTP-version: GET index.html HTTP/1.1
2、GET和POST
- GET比POST更不完全,因为参数直接暴露在URL上
- GET通过URL传递参数,POST可以放在Rquest body
- GET会产生一个TCP数据包,而POST会产生康哥TCP数据包(标准)
3、请求头
4、请求正文
5、HTTP缓存
1、强制缓存
- 当缓存服务器中有客户端需要的数据,直接拿来用(数据没有实效)
- Expires 和 Cache-Control
- 现在大部分都用Cache-Control
- private:客户端可以缓存
- public:客户端和代理服务器都可以
- max-age=t:缓存内容将在t秒后失效
- no-catche:使用协商缓存
- 现在大部分都用Cache-Control
2、协商缓存
- 也叫对比缓存,客户端会先从缓存数据库中拿到一个缓存的标识,然后向服务器端验证标识是否失效,如果没有实效,会返回304,这样客户端就可以之际去缓存数据库中拿出数据,如果失效,服务器端会返回新的数据。
- Last-Modified:服务器咋相应请求时,告诉浏览器资源的最后修改时间。如果资源被修改,那么直接返回200,否则只需要传输respone header,返回304
- Etag:相应服务器请求时候,通过此子端告诉浏览器当前资源在服务器生成的唯一标识(规则由服务器定)
3、通过缓存加快网页端的加载速度
5、服务器处理请求并返回HTTP报文
1、HTTP状态码
- 1xx:请求已收到
- 2xx:成功
- 3xx :发生了重定向
- 301:永久重定向
- 302:临时重定向
- 4xx :客户端错误-路径不正确/语法错误
- 401:鉴权错误
- 403:禁止
- 404:没有找到网页
- 5xx :服务器错误
- 500:服务器内部错误
- 502:服务器部署问题
2、响应报头
- Server,Connection
3、响应报文
- 请求的HTML、CSS等等
6、浏览器解析渲染页面
1、解析HTML形成DOM树
- 根据当前HTML内容,将标签按照结构解析成DOM树,DOM树的解析过程是一个深度优先遍历的方式。即现构建当前节点的所有子节点,再构建下一个兄弟节点
- 如果遇到script标签,则DOM树的构建会暂停,知道脚本下载并执行完成后继续构建
2、解析CSS形成CSSOM树
- 解析CSS形成CSS规则树,解析CSS规则树时JS执行将会暂停,直到CSS规则树就绪
- 浏览器在CSS规则树生成之前不会进行渲染
3、合并DOM树和CSSOM树形成渲染树
- DOM树和CSSOM树都准备好了后,浏览器会开始构建渲染树。
4、根据渲染树计算每一个节点信息(布局Layout)
- 布局:通过渲染树中渲染对象的信息,计算出每一个渲染对象的位置和尺寸
- 回流:在布局完成后,发现某个部分发生了变化影响了布局,就需要倒回去重新渲染
5、根据计算好的信息绘制页面
- 绘制阶段系统会遍历呈现树,并调用呈现器的"paint"方法,将呈现器的内容显示在屏幕上
- 重绘:某个元素的背景颜色、文字颜色等。不影响元素周围或内部布局的属性,将只会引起浏览器的重绘
- 回流:某个元素的尺寸发生变化,则需要重新计算渲染树
- 触发回流的时机:
- 首次渲染
- 浏览器窗口大小发生变化
- 元素尺寸或位置发生改变
- 内容变化(文字内容)
- 天假或删除DOM元素
- 激活css伪类:hover
- 查询某些属性或者调用某些方法
- clientWidth
- offsetWidth
- getComputedStyle()
- scrollTo()
- 触发回流的时机:
- 回流和重绘
- 比如color、background-color、vsilillity等等,浏览器会将新样式赋予给元素并重新绘制它
7、JS解析
浏览器开始加载HTML页面,遇到<script>标签,会根据标签的属性(defer/async)来决定如何处理脚本
1、预解析
- 同步脚本
- async 异步脚本:会解析HTML,同时异步下载脚本。脚本下载完后,会暂停解析立即执行脚本,脚本执行完成后,继续解析HTML
- defer 延迟脚本:会解析HTML。同时异步下载脚本。脚本会在HTML解析完成后,DOMContentLoaded触发前,按照脚本书写顺序依次执行。
2、浏览器引擎去执行JS:
- V8(chorme)、JSCORE(safira)
- 编译
- 词法分析
- 语法分析
- 代码生成
- 通过字节码去执行
- 执行
- 执行上下文和作用域
- JS引擎会创建执行上下文(context),包含变量对象、作用域链和this
- JS事件循环
- 执行上下文和作用域
8、页面渲染
当所有资源都加载和执行后,页面会显示给用户,这个过程会触发一些事件,如:DOMContentLoaded、load
1、定义:
- 触发时机:当初始的HTML文档被完全加载和解析之后触发
- 不等待资源:它不需要等待样式表(CSS)、图片(Images)、子框架(iframes)、异步脚本(带有async属性的script)加载完成
- 目标对象:事件目标是 document,但会冒泡到 window。
2、DOMContentLoaded VS window.onload
|----------|-------------------------|-------------------------------------------------|
| 特性 | DOMContentLoaded | window.onload(load 事件) |
| 触发条件 | DOM树构建完成 | 页面所有资源(DOM + CSS + Images + iframes等)全部加载完成 |
| 触发速度 | 快(一般远早于onload) | 慢(取决于图片、视频等资源大小) |
| 适用场景 | 操作DOM元素、绑定事件监听器、初始化UI逻辑 | 获取图片尺寸、操作Canvas、依赖外部资源完全加载的场景 |
| 多次绑定 | 支持多次添加监听器 | 通常只支持一个处理函数(若直接赋值window.onload = ...会覆盖之前的) |
3、执行事例
javascript// 1. HTML 解析开始 document.addEventListener('DOMContentLoaded', () => { console.log('1. DOM 解析完毕,可以操作 DOM 节点了'); // 此时图片可能还没加载完 }); window.addEventListener('load', () => { console.log('2. 所有资源(包括图片)加载完毕'); }); // 3. HTML 解析结束,触发 DOMContentLoaded // 4. 图片等资源加载结束,触发 load
9、常见问题及解决方案
1、<script>标签中的 async 和 defer。
1、用途:为什么需要 async 和 defer
没有属性的普通 <script>标签,遇到就会阻塞DOM解析,等它下载并执行完才会继续解析。如果脚本很大,页面就是白屏。async 和 defer 都能让脚本不阻塞DOM解析,DOM解析与脚本的下载过程是并行的,页面该解析解析。
2、区别:执行实际 + 顺序 + 与 DOMContentLoaded的关系
- 执行顺序:
- 普通script:遇到->下载->执行->继续解析
- defer:遇到->异步下载(不阻塞)->DOM解析完成后->按书写顺序执行->触发DOMContebtLoaded。
- async:遇到->异步下载->下载完成后立即执行(可能会阻塞解析)->执行完成后继续解析。(执行顺序不保证,谁先下载完谁先执行)
- 关键区别:
- 顺序:defer 保证顺序,async不保证顺序
- 执行时机:defer在DOM解析完成后、DOMContentLoaded前执行。async脚本文件下载完成后会立即执行,可能会在解析过程中执行,从而影响DOM解析。
- DOMContentLoaded触发:defer 会等待对应脚本执行完成后触发;async 不确定,如对应的脚本文件在DOM解析完成前下载并完成执行,不影响触发时机。
3、实际应用场景:选型
- defer :多个脚本有依赖关系 (如jq在前,插件在后),或脚本需要操作完整的DOM。
- async :独立脚本,不依赖其他脚本和DOM状态,比如埋点统计、广告脚本、第三方小程序。
- 普通:远古方案,现在基本上被defer替代
- 陷阱:
- 如果页面里有async的脚本在操作DOM,而DOM还没有解析完成,就可能报错,所以操作DOM的脚本不用async
2、点击切换样式,页面依旧卡顿掉帧?
1、业务分级,区分动态渲染和静态渲染。
动态频繁变更元素,直接脱离标准文档流,使用绝对定位布局,修改样式仅触发重绘,避免回流。静态固定展示元素,统一编写CSS类名,页面初始化一次性渲染完成,杜绝反复修改。
2、样式合并与兜底优化。
统一操作样式,摒弃逐行修改行内样式,通过切换class类名批量更改样式属性。DOM批量处理,新增页面元素使用文档碎片统一插入,减少页面渲染次数。硬件加速加持,动画家伙优先使用 transform 和 opacity,从根源避开回流触发条件。
3、架构层优化,降低渲染消耗。
长列表场景介入虚拟列表,只渲染可视区域DOM节点,从源头减少渲染压力。高频交互添加截流限制,滚动切换、点击联动操作限制执行频次,减少无效渲染。紧急场景降级开关,流量高峰关闭页面非必要动画特效,牺牲视觉效果有限保障页面流畅运行。
3、页面加载慢怎么优化?
1、优化方向:从"请求-渲染'全链路分层
- 网络层:
- DNS预解析(<link rel="dns-prefetch">);
- 减少HTTP请求(合并、雪碧图、iconfont);
- 开启HTTP/2(多路复用,减少队头阻塞);
- CDN(不仅加速,还降低带宽压力;CDN能减少RTT、提升并发能力)
- 资源层:
- 压缩:Gzip/Brotli、图片WebP/AVIF;
- 缓存:强缓存(Cache-Control) + 协商缓存(ETag);
- 按需加载:路由懒加载、图片懒加载
- 渲染层:
- 关键渲染路径优化:内联关键CSS,异步加载非关键JS(defer/async);
- 减少重排重绘:用transform 代替 left/top,读写DOM批量操作;
- 骨架屏 + 预加载(<link rel="preload">)
2、定位问题:使用工具反向推理
- 使用 Chrome DevTools 工具分析:
- Network:看资源耗时;
- Performance面板:看火焰图,分析是js执行时间长?解析HTML时间长?重排重绘频繁?
- Lighthouse:给出具体的评分和优化建议
- 从用户感知反推:
- 首屏加载:用SSR或预渲染解决白屏问题
- 交互可用:用代码分割,让首屏JS体积减小;
- 慢网络:用Service Worker做离线缓存
- 降级方案:兼容低端机,慢网络
- 低质量图片,禁用非必要动画,减少长任务。
3、避坑:
- CDN不是越多越好:多域名会增加DNS查询和连接开销,一般2~3个域名为宜
- 合并请求不一定更快:在HTTP/2下,小请求可以并行执行,合并反而会造成"一个资源阻塞全部"。
- 缓存不是越多越好:HTML不能强缓存太长,否则更新不生效。JS/CSS用内容哈希实现长效缓存。