一 单线程的枷锁与突破
核心问题
JavaScript主线程需要同时处理:
-
用户点击/滚动等交互事件
-
页面渲染更新
-
复杂计算任务
典型卡顿场景
// 同步执行耗时计算导致界面冻结
function processData() {
const data = generateLargeDataset(); // 生成10万条数据
data.forEach(item => { // 阻塞主线程
item.value = heavyCalculation(item);
});
renderResults(data); // 此时用户界面已卡死3秒
}
二 Web Workers:后台线程的救赎
基本使用流程

具体实现
主线程代码
// 创建Worker
const worker = new Worker('task.js');
// 发送任务
worker.postMessage({
type: 'CALCULATE',
data: generateLargeDataset()
});
// 接收结果
worker.onmessage = e => {
renderResults(e.data);
};
worker.js 文件内容
self.onmessage = function(e) {
if(e.data.type === 'CALCULATE') {
const result = e.data.data.map(heavyCalculation); // 在Worker线程执行
self.postMessage(result);
}
};
限制注意:
-
不能操作DOM
-
需通过
postMessage传递数据(数据会被复制而非共享)
三 任务分片:时间切片技术
优化长任务的经典模式
function processInChunks(data, chunkSize = 100) {
let index = 0;
function doChunk() {
const end = Math.min(index + chunkSize, data.length);
while(index < end) {
processItem(data[index++]);
}
if(index < data.length) {
// 让出主线程控制权
setTimeout(doChunk, 0);
// 或使用更现代的API:
// requestIdleCallback(doChunk);
}
}
doChunk();
}
效果对比:
|
处理方式 |
总耗时 |
用户感知卡顿 |
交互响应延迟 |
|---|---|---|---|
|
同步处理 |
2.1秒 |
严重卡死 |
超过2000ms |
|
分片处理 |
2.3秒 |
无卡顿 |
小于50ms |
四 高频事件优化:防抖与节流
滚动事件优化示例
// 原始版本:滚动时疯狂执行
window.addEventListener('scroll', handleScroll);
// 节流版:每100ms至多执行一次
function throttle(fn, delay) {
let lastCall = 0;
return function(...args) {
const now = Date.now();
if(now - lastCall >= delay) {
fn.apply(this, args);
lastCall = now;
}
};
}
// 防抖版:停止滚动后执行
function debounce(fn, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// 根据场景选择:
window.addEventListener('scroll', throttle(handleScroll, 100));
适用场景对比:
|
模式 |
典型案例 |
实现重点 |
|---|---|---|
|
节流 |
滚动加载更多 |
保证周期性执行 |
|
防抖 |
搜索框输入提示 |
等待操作停顿后执行 |
五 Promise的陷阱与优化
微任务堆积问题
// 危险的递归微任务
function recursivePromise() {
return Promise.resolve().then(() => {
doSomething();
recursivePromise(); // 微任务队列永远清空不完
});
}
优化策略:
// 正确:适时让出控制权
async function optimizedLoop() {
while(condition) {
await doWork();
// 每100次迭代插入宏任务
if(counter % 100 === 0) {
await new Promise(resolve => setTimeout(resolve, 0));
}
}
}
六 实战:图片懒加载综合优化
完整方案要点:
-
使用
Intersection Observer API监听可视区域 -
滚动时使用节流处理
-
Web Worker预解码图片数据
-
加载完成后使用
requestAnimationFrame更新DOM
核心代码片段:
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if(entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src; // 触发加载
observer.unobserve(img); // 停止观察
}
});
});
document.querySelectorAll('.lazy-img').forEach(img => {
observer.observe(img); // 开始观察
});
本章重点总结
- 线程转移:用Web Workers处理CPU密集型任务
- 任务切片:通过分块执行保持主线程响应
- 事件调控:防抖节流控制高频触发
- 异步调度:合理使用宏任务/微任务
1352

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



