加载时优化
从一个http请求发生(从输入URL到页面加载的全过程)的详细过程中发掘一些可优化点
一、 减少DNS查询, 使用合理范围内的多个域名
保持2~4个域名的折中方案,最大化下载线程(现代浏览器会有同域名限制并发下载数的情况),同时又可以一定程度的减少DNS解析的过程
二、减少http请求数量、请求大小
- 图片使用精灵图,减少http请求数量
- 压缩文件减少http请求大小
- 合并文件减少http请求数量
三、使用CDN加载静态资源
缓存源站的资源到各cdn节点上,用户就近获取资源,缓解服务器压力,提升响应速度
四、按需加载,减少冗余代码
图片懒加载
核心思路:监听页面滚动事件,图片出现在可视区域内则进行加载显示// 监听滚动事件 img.src = img.getAttribute("data-src")
- 减少babel转译过程中的冗余代码
使用@babel/plugin-transform-runtime
按需引入@babel/runtime中的辅助函数(helper)
五、服务端渲染SSR
服务端解析html内容, 浏览器端直接渲染
实现方式:
(1) JSP
(2) vue + nuxt
(3) express + react
与客户端渲染CSR的区别:
SSR利于首屏渲染、SEO优化;CSR适用于交互性强、不需要SEO的项目
部分场景混合搭配使用,例如next.js
六、css放头部,js置底部
保证页面正常渲染,js需要放头部可给script添加defer属性
用于延迟加载
运行时优化(代码优化)
一、函数防抖、节流
两种实现方式:定时器和时间戳
- 函数防抖
事件触发后经过一段时间触发响应,在这段时间内若再次触发则重新计时, 即"只有最后一次操作被触发"
function debounce(fn, delay) {
let timerId = null;
return function (...args) {
const context = this;
timerId && clearTimeout(timerId);
timerId = setTimeout(() => {
fn.apply(context, args);
}, delay);
};
}
const callback = function (e, data1) {
console.log(e, data1);
};
document.addEventListener('mousemove', debounce(callback, 3000));
应用场景:输入框搜索、输入框输入验证、浏览器窗口resize
- 函数节流
指定时间间隔内,只执行一次
function throttle(fn, delay, params) {
let timerId = null;
return function (...args) {
const context = this;
if (!timerId) {
timerId = setTimeout(() => {
timerId = null;
fn.apply(context, args);
}, delay);
}
};
}
const callback = function (e, data1) {
console.log(e, data1);
};
document.addEventListener('mousemove', throttle(callback, 3000));
应用场景:长列表滚动加载、频繁点击事件(点赞、表单提交等操作)、输入框自动补全
二、减少重排和重绘
三、代码上的细节优化
- 尾调用优化
只保留内层函数的调用帧, 用于解决js引擎最大递归深度问题(即最大嵌套调用次数, 一般为100000次)
目前大部分浏览器不支持
应用:尾递归
// 递归遍历
let company = {
sales: [{name: 'John', salary: 1000}, {name: 'Alice', salary: 1600 }],
development: {
sites: [{name: 'Peter', salary: 2000}, {name: 'Alex', salary: 1800 }],
internals: [{name: 'Jack', salary: 1300}]
}
};
function sumSalaries(department) {
if (Array.isArray(department)) {
return department.reduce((prev, current) => prev + current.salary, 0);
} else {
let sum = 0;
for (let subdep of Object.values(department)) {
sum += sumSalaries(subdep);
}
return sum;
}
}
alert(sumSalaries(company)); // 7700
// 递归结构
例如链表结构,对于插入、删除操作,优于数组
let list = {
value: 1,
next: {
value: 2,
next: {
value: 3,
next: {
value: 4,
next: null
}
}
}
};
// 尾递归优化
function Fibonacci1 (n , ac1 = 1 , ac2 = 1) {
if( n <= 2 ) {return ac2};
return Fibonacci1 (n - 1, ac2, ac1 + ac2);
}
Fibonacci1(7) // 13