1、使用 Web Workers 和 Service Workers 来提高并行性和离线缓存。
使用 Web Workers 和 Service Workers:可以使用 Web Workers 将计算密集型任务放到其他线程中执行,以避免卡顿和阻塞 UI 线程。Service Workers 可以用于缓存网页资源以提高加载速度和离线访问能力。
// 创建一个 Web Worker 并执行任务
const worker = new Worker('worker.js');
worker.postMessage({ task: 'heavy computation' });
// 在 Service Worker 中缓存资源
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request).then(res =>
caches.open('v1').then(cache => {
cache.put(event.request, res.clone());
return res;
})
);
})
);
});
2、使用 HTTP/2 来减少请求次数和加快加载速度。
使用 HTTP/2:HTTP/2 支持多路复用、服务器推送等特性,可以减少请求次数和加快页面加载速度。
<!-- 不需要使用多个 script 标签 -->
<script src="all.js" type="module"></script>
3、采用懒加载和分块加载来避免不必要的资源消耗和提高用户体验。
懒加载和分块加载:可以使用 Intersection Observer API 或者手动监听滚动事件实现懒加载。分块加载可以使用 import() 函数来实现。
// 使用 Intersection Observer API 实现图片懒加载
const images = document.querySelectorAll('img.lazyload');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
});
images.forEach(img => {
observer.observe(img);
});
// 使用 import() 函数实现分块加载
import('./lazy-load.js').then(module => {
module.init();
});
4、使用图片压缩、CSS Sprite、字体子集化等技术来减小资源大小和提高加载速度。
图片压缩、CSS Sprite、字体子集化:可以使用工具如 ImageOptim、TinyPNG、webfont-generator 等来处理图片和字体文件。
/* 将多个小图片合并成一个大图 */
.icon {
background-image: url(sprites.png);
background-position: -10px -20px;
width: 32px;
height: 32px;
}
/* 使用 WOFF2 字体格式来减小字体文件大小 */
@font-face {
font-family: 'My Custom Font';
src: url('my-custom-font.woff2') format('woff2'),
url('my-custom-font.woff') format('woff');
font-weight: normal;
font-style: normal;
}
/* 使用 TinyPNG 等工具来压缩图片 */
5、使用缓存策略来减少网络请求,如使用 Cache-Control、Expires、ETag 等头部信息。
缓存策略:可以在服务器端设置 Cache-Control、Expires、ETag 等头部信息,也可以使用浏览器本地缓存。
// 在服务器端设置 Cache-Control 头部信息
app.use(express.static('public', { maxAge: '1d' }));
// 在客户端使用 localStorage 缓存数据
const data = localStorage.getItem('data');
if (data) {
// 使用缓存的数据
} else {
fetch(url)
.then(response => response.json())
.then(data => {
localStorage.setItem('data', data);
// 使用新数据
});
}
6、对于动画效果,应该尽量使用 CSS 动画而非 JavaScript 实现以获得更好的性能表现。
CSS 动画:可以使用 transform 和 opacity 等属性来实现 CSS 动画效果,比起 JavaScript 实现更流畅。
/* 使用 transform 和 opacity 来实现 CSS 动画效果 */
.fade-in {
opacity: 0;
transition: opacity 500ms ease-out;
}
.fade-in.visible {
opacity: 1;
}
7、避免在页面加载时执行过多的 JavaScript 代码,可以使用惰性加载或异步加载技术。
JavaScript 加载:可以使用 defer、async 属性或者动态创建 script 标签实现惰性加载或异步加载 JavaScript 脚本。
<!-- 使用 defer 属性延迟脚本执行 -->
<script defer src="app.js"></script>
<!-- 使用动态创建 script 标签实现异步加载 -->
<button onclick="loadScript()">Load Script</button>
function loadScript() {
const script = document.createElement('script');
script.src = 'app.js';
script.async = true;
document.body.appendChild(script);
}
8、使用浏览器兼容性良好的 API 和框架,如使用 requestIdleCallback 来优化资源加载等。
浏览器兼容性:可以使用 polyfill 或者框架库如 React、Vue 等来实现兼容性良好的代码。
// 使用 polyfill 实现兼容性
if (!String.prototype.includes) {
String.prototype.includes = function(search, start) {
'use strict';
if (typeof start !== 'number') {
start = 0;
}
if (start + search.length > this.length) {
return false;
} else {
return this.indexOf(search, start) !== -1;
}
};
}
// 使用框架库实现兼容性
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
9、考虑代码拆分和代码分析来减小 JavaScript Bundle 大小和提高渲染速度。
代码拆分和分析:可以使用工具如 webpack、rollup、source-map-explorer 等来实现代码拆分和分析。
// 使用 webpack 实现代码拆分
// webpack.config.js
module.exports = {
entry: './index.js',
output: {
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
},
optimization: {
splitChunks: {
chunks: 'all',
},
},
};
详请查看:使用 source-map-explorer 分析代码大小
10、使用性能监控和分析工具来检测和解决性能问题,如使用 Lighthouse、Chrome DevTools 等。
性能监控和分析:可以使用 Google Analytics、Lighthouse、Chrome DevTools 等工具来监控和分析网站性能。
// 使用 Google Analytics 监控网站性能
function trackPerformance() {
if (window.performance && window.performance.timing) {
const timing = window.performance.timing;
const loadTime = timing.loadEventEnd - timing.navigationStart;
ga('send', 'timing', 'page load', 'load time', loadTime);
}
}
window.addEventListener('load', trackPerformance);
// 使用 Lighthouse 分析网站性能
/* 在 Chrome DevTools 中打开 Audits 面板并运行测试 */