
个人主页:Guiat
归属专栏:HTML CSS JavaScript

正文
1. JavaScript 性能优化
1.1 代码优化
1.1.1 减少 DOM 操作
DOM 操作是昂贵的,应尽量减少:
// 低效: 多次单独操作 DOM
for (let i = 0; i < 1000; i++) {
document.body.innerHTML += '<div>' + i + '</div>';
}
// 高效: 批量操作后一次性更新 DOM
let html = '';
for (let i = 0; i < 1000; i++) {
html += '<div>' + i + '</div>';
}
document.body.innerHTML = html;
// 更高效: 使用文档片段
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const div = document.createElement('div');
div.textContent = i;
fragment.appendChild(div);
}
document.body.appendChild(fragment);
1.1.2 使用事件委托
利用事件冒泡,在父元素上处理子元素事件:
// 低效: 为每个按钮添加事件监听器
document.querySelectorAll('button').forEach(button => {
button.addEventListener('click', function(e) {
console.log('Button clicked:', this.textContent);
});
});
// 高效: 使用事件委托
document.querySelector('.button-container').addEventListener('click', function(e) {
if (e.target.tagName === 'BUTTON') {
console.log('Button clicked:', e.target.textContent);
}
});
1.1.3 避免全局变量
全局变量会降低变量查找速度并增加命名冲突风险:
// 不推荐: 全局变量
var count = 0;
function increment() {
count++;
}
// 推荐: 使用模块或闭包
const counter = (function() {
let count = 0;
return {
increment() { count++; },
getCount() { return count; }
};
})();
1.1.4 优化循环
const arr = [1, 2, 3, 4, 5];
// 低效: 每次迭代都计算数组长度
for (let i = 0; i < arr.length; i++) { /* ... */ }
// 高效: 缓存数组长度
for (let i = 0, len = arr.length; i < len; i++) { /* ... */ }
// 现代方法: 使用数组方法
arr.forEach(item => { /* ... */ });
// 或
for (const item of arr) { /* ... */ }
1.2 资源加载优化
1.2.1 脚本加载策略
<!-- 阻塞渲染的脚本 -->
<script src="script.js"></script>
<!-- 异步加载,不阻塞渲染,但加载完立即执行 -->
<script async src="script.js"></script>
<!-- 延迟加载,不阻塞渲染,在HTML解析完成后按顺序执行 -->
<script defer src="script.js"></script>
1.2.2 懒加载
// 图片懒加载示例
document.addEventListener('DOMContentLoaded', function() {
const lazyImages = document.querySelectorAll('img.lazy');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.remove('lazy');
observer.unobserve(img);
}
});
});
lazyImages.forEach(img => observer.observe(img));
});
1.3 渲染优化
1.3.1 避免布局抖动(Layout Thrashing)
// 低效: 强制多次重排
const boxes = document.querySelectorAll('.box');
boxes.forEach(box => {
const height = box.offsetHeight; // 读取
box.style.height = (height * 2) + 'px'; // 写入
const width = box.offsetWidth; // 读取
box.style.width = (width * 2) + 'px'; // 写入
});
// 高效: 批量读取后批量写入
const boxes = document.querySelectorAll('.box');
// 读取阶段
const dimensions = Array.from(boxes).map(box => ({
height: box.offsetHeight,
width: box.offsetWidth
}));
// 写入阶段
boxes.forEach((box, i) => {
box.style.height = (dimensions[i].height * 2) + 'px';
box.style.width = (dimensions[i].width * 2) + 'px';
});
1.3.2 使用 requestAnimationFrame
// 低效: 使用setTimeout进行动画
function animate() {
element.style.left = (parseFloat(element.style.left) || 0) + 1 + 'px';
setTimeout(animate, 16); // 约60fps
}
// 高效: 使用requestAnimationFrame
function animate() {
element.style.left = (parseFloat(element.style.left) || 0) + 1 + 'px';
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
2. JavaScript 安全
2.1 XSS (跨站脚本攻击)
2.1.1 XSS 攻击示例
// 危险: 直接插入用户输入
const userInput = '<script>alert("XSS攻击!")</script>';
document.getElementById('output').innerHTML = userInput;
// 安全: 转义用户输入
function escapeHTML(str) {
return str.replace(/[&<>"']/g, m => ({
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
}[m]));
}
document.getElementById('output').innerHTML = escapeHTML(userInput);
2.1.2 防御 XSS
- 内容安全策略 (CSP)
<!-- 在HTML头部添加CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
- 使用 textContent 而非 innerHTML
// 安全: 使用textContent
document.getElementById('output').textContent = userInput;
- 使用现代框架的自动转义功能
// React自动转义
function App() {
const userInput = '<script>alert("XSS")</script>';
return <div>{userInput}</div>; // React自动转义
}
2.2 CSRF (跨站请求伪造)
2.2.1 CSRF 攻击示例
攻击者可能在恶意网站上放置如下代码:
<img src="https://bank.example/transfer?to=attacker&amount=1000" style="display:none">
2.2.2 防御 CSRF
- 使用 CSRF Token
// 服务器生成token并发送给客户端
const csrfToken = generateRandomToken();
// 客户端发送请求时附带token
fetch('/api/transfer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken
},
body: JSON.stringify(data)
});
- 使用 SameSite Cookie 属性
// 服务器设置Cookie
document.cookie = "sessionId=abc123; SameSite=Strict";
2.3 输入验证与净化
// 客户端验证
function validateEmail(email) {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email);
}
// 数据净化
function sanitizeInput(input) {
// 移除所有HTML标签
return input.replace(/<[^>]*>/g, '');
}
2.4 安全的 JSON 解析
// 危险: 使用eval解析JSON
const userData = eval('(' + jsonString + ')'); // 不安全!
// 安全: 使用JSON.parse
try {
const userData = JSON.parse(jsonString);
} catch (e) {
console.error('Invalid JSON');
}
2.5 避免原型污染
// 危险: 直接合并用户提供的对象
Object.assign(config, userProvidedConfig);
// 安全: 使用Object.create(null)创建无原型对象
const safeConfig = Object.create(null);
for (const key in userProvidedConfig) {
if (Object.prototype.hasOwnProperty.call(userProvidedConfig, key) && key !== '__proto__') {
safeConfig[key] = userProvidedConfig[key];
}
}
2.6 使用 HTTPS
确保所有API请求和资源加载使用HTTPS:
// 强制重定向到HTTPS
if (location.protocol !== 'https:') {
location.replace(`https:${location.href.substring(location.protocol.length)}`);
}
2.7 安全的本地存储
// 敏感数据不应存储在localStorage
// 不安全:
localStorage.setItem('authToken', token);
// 更安全: 使用sessionStorage或加密后存储
sessionStorage.setItem('authToken', token);
// 或使用加密库加密后存储
const encryptedToken = encryptData(token, secretKey);
localStorage.setItem('authToken', encryptedToken);
3. 高级性能优化技术
3.1 Web Workers
将耗时计算移至后台线程:
// main.js
const worker = new Worker('worker.js');
worker.onmessage = function(e) {
console.log('计算结果:', e.data);
};
worker.postMessage({numbers: [1, 2, 3, 4, 5]});
// worker.js
self.onmessage = function(e) {
const numbers = e.data.numbers;
const result = numbers.reduce((sum, num) => sum + num, 0);
self.postMessage(result);
};
3.2 内存管理
// 避免内存泄漏
function createNodes() {
const nodes = [];
for (let i = 0; i < 10000; i++) {
nodes.push(document.createElement('div'));
}
// 不好: 未清理引用
// return nodes;
// 好: 使用后清理引用
const result = doSomethingWith(nodes);
nodes.length = 0; // 清空数组
return result;
}
3.3 使用缓存
// 函数结果缓存 (记忆化)
function memoize(fn) {
const cache = {};
return function(...args) {
const key = JSON.stringify(args);
if (!(key in cache)) {
cache[key] = fn.apply(this, args);
}
return cache[key];
};
}
const expensiveCalculation = memoize(function(n) {
console.log('计算中...');
return n * n;
});
console.log(expensiveCalculation(4)); // 输出: 计算中... 16
console.log(expensiveCalculation(4)); // 输出: 16 (使用缓存)
3.4 虚拟列表
处理大量数据时,只渲染可视区域内的元素:
class VirtualList {
constructor(container, itemHeight, totalItems, renderItem) {
this.container = container;
this.itemHeight = itemHeight;
this.totalItems = totalItems;
this.renderItem = renderItem;
this.visibleItems = Math.ceil(container.clientHeight / itemHeight) + 2;
this.scrollTop = 0;
this.startIndex = 0;
this.init();
}
init() {
this.container.style.position = 'relative';
this.container.style.overflow = 'auto';
this.container.style.height = '100%';
const totalHeight = this.totalItems * this.itemHeight;
this.content = document.createElement('div');
this.content.style.height = `${totalHeight}px`;
this.content.style.position = 'relative';
this.container.appendChild(this.content);
this.items = [];
for (let i = 0; i < this.visibleItems; i++) {
const item = document.createElement('div');
item.style.position = 'absolute';
item.style.width = '100%';
item.style.height = `${this.itemHeight}px`;
this.content.appendChild(item);
this.items.push(item);
}
this.container.addEventListener('scroll', this.onScroll.bind(this));
this.render();
}
onScroll() {
this.scrollTop = this.container.scrollTop;
this.render();
}
render() {
this.startIndex = Math.floor(this.scrollTop / this.itemHeight);
for (let i = 0; i < this.visibleItems; i++) {
const index = this.startIndex + i;
const item = this.items[i];
if (index < this.totalItems) {
item.style.top = `${index * this.itemHeight}px`;
item.style.display = 'block';
this.renderItem(item, index);
} else {
item.style.display = 'none';
}
}
}
}
// 使用示例
const container = document.getElementById('list-container');
const virtualList = new VirtualList(
container,
50, // 每项高度50px
10000, // 总共10000项
(element, index) => {
element.textContent = `Item ${index}`;
element.style.backgroundColor = index % 2 ? '#f0f0f0' : '#fff';
}
);
4. 性能监控与分析
4.1 使用性能API
// 测量代码执行时间
performance.mark('start');
// 执行代码...
performance.mark('end');
performance.measure('执行时间', 'start', 'end');
const measures = performance.getEntriesByType('measure');
console.log(`执行时间: ${measures[0].duration}ms`);
// 监控资源加载时间
window.addEventListener('load', () => {
const resources = performance.getEntriesByType('resource');
resources.forEach(resource => {
console.log(`${resource.name}: ${resource.duration}ms`);
});
});
4.2 使用Chrome开发者工具
// 使用console.time测量性能
console.time('操作');
// 执行代码...
console.timeEnd('操作');
// 分析内存使用
console.memory;
5. 框架特定优化
5.1 React优化
// 使用React.memo避免不必要的重渲染
const MemoizedComponent = React.memo(function MyComponent(props) {
// 组件逻辑
});
// 使用useCallback缓存函数引用
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
// 使用useMemo缓存计算结果
const memoizedValue = useMemo(() => {
return computeExpensiveValue(a, b);
}, [a, b]);
5.2 Vue优化
// 使用v-once渲染一次性内容
<span v-once>{{ neverChanges }}</span>
// 使用v-memo缓存模板部分
<div v-memo="[valueA, valueB]">
<!-- 只有当valueA或valueB变化时才会更新 -->
</div>
// 使用计算属性缓存结果
computed: {
expensiveComputation() {
return this.items.filter(/* 复杂计算 */);
}
}
6. 安全最佳实践
6.1 安全的第三方库使用
// 使用子资源完整性(SRI)确保第三方库未被篡改
<script
src="https://cdn.example.com/library.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous">
</script>
6.2 安全的正则表达式
防止正则表达式拒绝服务攻击(ReDoS):
// 危险: 容易受到ReDoS攻击的正则表达式
const dangerousRegex = /^(a+)+$/;
dangerousRegex.test('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!');
// 安全: 限制重复次数
const safeRegex = /^(a+){1,10}$/;
6.3 iframe安全
<!-- 使用sandbox和CSP限制iframe权限 -->
<iframe
src="https://third-party.com"
sandbox="allow-scripts allow-same-origin"
allow="camera 'none'; microphone 'none'; geolocation 'none'"
></iframe>
7. 总结
JavaScript性能优化和安全是相辅相成的。良好的性能优化实践通常也能提高代码的安全性,而安全的代码实现也往往有助于提升应用性能。开发者应当在项目初期就考虑这两个方面,并在整个开发周期中持续关注和改进。
关键点总结:
-
性能优化:
- 减少DOM操作,使用事件委托
- 优化资源加载,使用懒加载
- 避免布局抖动,使用requestAnimationFrame
- 利用Web Workers处理复杂计算
- 实现虚拟列表处理大量数据
-
安全防护:
- 防御XSS攻击,转义用户输入
- 防御CSRF攻击,使用Token和SameSite Cookie
- 安全处理JSON,避免使用eval
- 防止原型污染
- 使用HTTPS和内容安全策略(CSP)
通过持续学习和应用这些最佳实践,可以构建既高效又安全的JavaScript应用。
结语
感谢您的阅读!期待您的一键三连!欢迎指正!


被折叠的 条评论
为什么被折叠?



