JS基础与高级应用: 性能优化
myzbx 2025-08-06 21:59 2 浏览
在现代Web开发中,性能优化已成为前端工程师必须掌握的核心技能之一。本文从URL输入到页面加载完成的全过程出发,深入分析了HTTP协议的演进、域名解析、代码层面性能优化以及编译与渲染的最佳实践。通过节流、防抖、重复请求合并等具体技术手段,全面提升Web应用的性能表现。本文不仅涵盖了理论知识,还提供了实用的代码示例,帮助读者在实际项目中快速应用这些优化策略。
一、从输入 URL 到页面加载完成都做了什么?
第一步: 从 输入 开始分析
URL 和 URI 的区别
URL: 资源定位符 | URI: 资源标识符 | www.baidu.com - http 协议
http 和 tcp 之间有什么关联和区别?
http 属于应用层协议, tcp 属于传输层协议
关联: http 是基于 tcp 实现连接的。udp 无连接、传输速度快、会丢包。
http 是如何建立连接的? 三次握手和四次挥手
HTTP 面向连接, 安全。但是传输速率相较低于 UDP , 每次请求前都需要建立连接。
优化方向: 回合制(session) 多路复用 | 压缩头部空间 | 合并请求-长连接
优化点: http1.0 http1.1 http2.0
HTTP1.0 存在的问题:
- 没有办法复用连接 | 1.1 复用连接 (持久连接, connection: keep-alive)
- 对头阻塞问题 (Head-of-Line Blocking,简称 HOL 阻塞) (下一个请求必须在前一个请求到达之后才可以进行); 1.1 => pipelining 解决对头阻塞问题
都是解决传输效率问题
HTTP 1.1 => 2.0: 2.0 解决的问题
- 头部空间: 协议层消除头部重复部分,利用算法对头信息压缩整合 ( 头部信息索引表 )。
- 1.0/1.1 纯文本格式 | 2.0 二进制优化, HTTP2.0 都是用二进制进行传输, 帧的形式。=> 多路复用(复用通路, 无并发限制)
HTTPS => HTTP + SSL协议
优化: 安全性建立导致网络请求加载时间延长。合并请求-长连接。
如何使用 HTTP 2.0 ?
第二步: 解析域名
地址转换成 IP: www.baidu.com => xxx.xxx.xxx.xxx | ARP 协议
IP 转成网址: RARP 协议
什么是 HOST? 如何切换 HOST? => 寻址
浏览器的缓存映射 → 系统缓存映射 → 路由器缓存映射 → 运营商缓存映射 → 根服务器
/etc/hosts localhost 127.0.0.1
实际静态文件存放: 机房、云服务站点 => 大流量问题 =>
配置多个 IP 地址、LB负载均衡、云服务
CDN 内容分发网络
缓存机制: 各级缓存 => 浏览器缓存 (304) - 强缓存(expire cache-control) / 协商缓存 last-modify、etag 找服务端进行验证是否需要缓存。
寻址、缓存
········································································································································································
二、代码层面性能优化
并发控制 QPS
- 浏览器请求上限 - 最大同时请求 6 条。
并发优化: 同时发出 20 条请求,但是由于服务或者业务需求, 我们的性能只能同时处理 3 个, 怎么去做?
分析:
输入: 参数 max - 最大的同时处理量
存储: reqpool - 并发池 (实时更新, 出去一个进来一个)
思路: 执行且回调, 实时加入添加。 执行 => 回调 => 塞入 => 返回 (循环)
js复制代码 class limitPromise {
constructor(max){
// 异步"并发"上限
this._max = max || 6
// 当前正在执行的任务数量 - 非满载场景
this._count = 0
// 等待执行的任务队列
this._taskQueue = []
// 实例 单例模式
}
// 执行的主入口
// caller 执行的请求
run(caller) {
// 主入口
// 输入外部要添加的
// 输出返回队列处理的 promise
return new Promise((resolve, reject)=>{
// 创建处理任务
const task = this._createTask(caller, resolve, reject)
// 当前队列是否拿到上限
if(this._count >= this._max){
// 超过最大数量, 不去执行, 放入待执行队列中
this._taskQueue.push(task)
} else {
task()
}
})
}
_createTask(caller, resolve, reject){
return () => {
caller().then(res =>{
resolve(res)
}).catch(err=>{
reject(res)
}).finally(()=>{
this._count--
if(this._taskQueue.length){
const task = this._taskQueue.shift()
task()
}
})
this._count++
}
}
static instance = null
static getInstance(max){
if(!this.instance){
this.instance = new limitPromise(max)
}
return this.instance
}
}
节流
js复制代码 function throttle(func, wait) {
let timeout = null;
let lastExecution = 0;
return function (...args) {
const context = this;
const now = Date.now();
if (lastExecution && now < lastExecution + wait) {
clearTimeout(timeout);
timeout = setTimeout(() => {
lastExecution = now;
func.apply(context, args);
}, wait - (now - lastExecution));
} else {
lastExecution = now;
func.apply(context, args);
}
};
}
function handleResize() {
console.log('Resize event triggered at', new Date().toLocaleTimeString());
}
// 创建一个节流函数,最多每1秒执行一次
const throttledResize = throttle(handleResize, 1000);
// 监听窗口调整大小事件
window.addEventListener('resize', throttledResize);
防抖
防抖(Debounce)是指在事件被触发后,等待一段时间再去执行函数。如果在等待时间内事件再次被触发,则重新开始计时。防抖的常见应用场景包括搜索框输入、窗口调整大小、按钮点击等需要防止频繁触发的情况。
防抖函数可以通过 setTimeout 和 clearTimeout 来实现。以下是一个通用的防抖函数实现:
js复制代码 function debounce(func, wait) {
let timeout;
return function (...args) {
const context = this;
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args);
}, wait);
};
}
function handleInput() {
console.log('Input event triggered at', new Date().toLocaleTimeString());
}
// 创建一个防抖函数,只有在最后一次输入后等待1秒才执行
const debouncedInput = debounce(handleInput, 1000);
// 监听输入事件
const inputElement = document.querySelector('input');
inputElement.addEventListener('input', debouncedInput);
扩展功能:立即执行选项
有时我们希望在事件触发后立即执行一次函数,并在等待时间内不再执行。可以通过增加一个 immediate 参数来实现:
js复制代码 function debounce(func, wait, immediate) {
let timeout;
return function (...args) {
const context = this;
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(() => {
timeout = null;
if (!immediate) func.apply(context, args);
}, wait);
if (callNow) func.apply(context, args);
};
}
<!---->
function handleInput() {
console.log('Input event triggered at', new Date().toLocaleTimeString());
}
// 创建一个防抖函数,在第一次输入时立即执行,之后等待1秒再执行
const debouncedInput = debounce(handleInput, 1000, true);
// 监听输入事件
const inputElement = document.querySelector('input');
inputElement.addEventListener('input', debouncedInput);
重复请求的合并
三、编译和渲染优化
打包优化 => 压缩、分割、按需加载、异步加载 => 工程化
渲染优化 => 重排和重绘 => 根据浏览器原理避免
线程阻塞 => JS 后置
内存分配: 即时释放
- 对象原则: 层级宜平不宜深, 尽量使用深拷贝(局部), 避免循环利用。
js复制代码<!---->
function foo(){
course = '' // 永远不会释放
this.course = ''
}
foo()
const timeoutId = setTimeout(()=>{}, 1000) // 定时器线程独立于JS线程
clearTimeout(timeoutId); // 清除定时器
function course{
const c = 'xxx'
return {
c
}
}
const tmp =course()
tmp = undefined // 销毁
- JS mark & sweep
mark 触达标记: 能够被访问到, 标记; 没有再能访问的 sweep。
相关推荐
- 零基础入门AI智能体:详细了解什么是变量类型、JSON结构、Markdown格式
-
当品牌跳出固有框架,以跨界联动、场景创新叩击年轻群体的兴趣点,一场关于如何在迭代中保持鲜活的探索正在展开,既藏着破圈的巧思,也映照着与新一代对话的密码。在创建AI智能体时,我们会调用插件或大模型,而在...
- C# 13模式匹配:递归模式与属性模式在真实代码中的性能影响分析
-
C#13对模式匹配的增强让复杂数据处理代码更简洁,但递归模式与属性模式的性能差异一直是开发者关注的焦点。在实际项目中,选择合适的模式不仅影响代码可读性,还可能导致执行效率的显著差异。本文结合真实测试...
- 零基础快速入门 VBA 系列 6 —— 常用对象(工作簿、工作表和区域)
-
上一节,我介绍了VBA内置函数以及如何自动打字和自动保存文件。这一节,我们来了解一下Excel常用对象。Excel常用对象Excel有很多对象,其中最常用也最重要的包括以下3个:1.Workbo...
- 不同生命数字的生肖龙!准到雷普!
-
属龙的人总在自信爆棚和自讨苦吃之间反复横跳?看完这届龙宝宝的日常我悟了。属龙的人好像天生自带矛盾体:领导力超强可人缘时好时坏,工作雷厉风行却总在爱情里翻车。关键年份的龙性格差异更大——76年龙靠谱但不...
- 仓颉编程语言基础-面向对象编程-属性(Properties)
-
属性是仓颉颉中一种强大的机制,它允许你封装对类(或接口interface、结构体struct、枚举enum、扩展extend)内部状态的访问。它看起来像一个普通的成员变量(字段),但在其背后,它通过...
- Python中class对象/属性/方法/继承/多态/魔法方法详解
-
一、基础入门:认识类和对象1.类和对象的概念在Python中,类(class)是一种抽象的概念,用于定义对象的属性和行为,而对象(也称为实例)则是类的具体表现。比如,“汽车”可以是一个类,它有...
- VBA基础入门:搞清楚对象、属性和方法就成功了一半
-
如果你刚接触VBA(VisualBasicforApplications),可能会被“对象”“属性”“方法”这些术语搞得一头雾水。但事实上,这三个概念是VBA编程的基石。只要理解它们之间的关系,...
- P.O类型文推荐|年度编推合集(一百九十五篇)
-
点击左上方关注获取更多精彩推文目录2019年度编推35篇(1V1)《悖论》作者:流苏.txt(1V1)《桂花蒸》作者:大姑娘浪.txt(1V1)《豪门浪女》作者:奚行.txt...
- Python参数传递内存大揭秘:可变对象 vs 不可变对象
-
90%的Python程序员不知道,函数参数传递中可变对象的修改竟会导致意想不到的副作用!一、参数传递的本质:对象引用传递在Python中,所有参数传递都是对象引用的传递。这意味着函数调用时传递的不是对...
- JS 开发者必看!TC39 2025 最新动向,这些新语法要火?
-
大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。TC39第...
- 2025 年值得尝试的 5 个被低估的 JavaScript 库
-
这些JavaScript库可能不会在社交媒体或HackerNews上流行起来,但它们会显著提高您的工作效率和代码质量。JavaScript不再只是框架。虽然React、Vue和Sv...
- Python自动化办公应用学习笔记30—函数的参数
-
一、函数的参数1.形参:o定义:在函数定义时,声明在函数名后面括号中的变量。o作用:它们是函数内部的占位符变量,用于接收函数被调用时传入的实际值。o生命周期:在函数被调用时创建,在函数执...
- 16种MBTI人格全解析|测完我沉默了三秒:原来我是这样的人?
-
MBTI性格测试火了这么久,你还不知道自己是哪一型?有人拿它当社交话题,有人拿它分析老板性格,还有人干脆当成择偶参考表。不废话,今天我一次性给你整理全部16种MBTI人格类型!看完你不仅能知道自己是谁...
- JS基础与高级应用: 性能优化
-
在现代Web开发中,性能优化已成为前端工程师必须掌握的核心技能之一。本文从URL输入到页面加载完成的全过程出发,深入分析了HTTP协议的演进、域名解析、代码层面性能优化以及编译与渲染的最佳实践。通过节...
- 爱思创CSP-J/S初赛模拟赛线上开赛!助力冲入2024年CSP-J/S复赛!
-
CSP-J/S组初赛模拟赛爱思创,专注信奥教育19年,2022年CSP-J/S组赛事指定考点,特邀NOIP教练,开启全真实CSP-J/S组线上初赛模拟大赛!一、比赛对象:2024年备考CSP-J/S初...
- 一周热门
- 最近发表
-
- 零基础入门AI智能体:详细了解什么是变量类型、JSON结构、Markdown格式
- C# 13模式匹配:递归模式与属性模式在真实代码中的性能影响分析
- 零基础快速入门 VBA 系列 6 —— 常用对象(工作簿、工作表和区域)
- 不同生命数字的生肖龙!准到雷普!
- 仓颉编程语言基础-面向对象编程-属性(Properties)
- Python中class对象/属性/方法/继承/多态/魔法方法详解
- VBA基础入门:搞清楚对象、属性和方法就成功了一半
- P.O类型文推荐|年度编推合集(一百九十五篇)
- Python参数传递内存大揭秘:可变对象 vs 不可变对象
- JS 开发者必看!TC39 2025 最新动向,这些新语法要火?
- 标签列表
-
- HTML 简介 (30)
- HTML 响应式设计 (31)
- HTML URL 编码 (32)
- HTML Web 服务器 (31)
- HTML 表单属性 (32)
- HTML 音频 (31)
- HTML5 支持 (33)
- HTML API (36)
- HTML 总结 (32)
- HTML 全局属性 (32)
- HTML 事件 (31)
- HTML 画布 (32)
- HTTP 方法 (30)
- 键盘快捷键 (30)
- CSS 语法 (35)
- CSS 轮廓宽度 (31)
- CSS 谷歌字体 (33)
- CSS 链接 (31)
- CSS 定位 (31)
- CSS 图片库 (32)
- CSS 图像精灵 (31)
- SVG 文本 (32)
- 时钟启动 (33)
- HTML 游戏 (34)
- JS Loop For (32)