虚拟列表滚动的时候,会触发很多次重排重绘,怎么优化
- 使用 CSS Transform 替代布局属性 原理:通过 transform: translateY 调整元素位置,利用 GPU 加速(合成层),避免触发重排(Layout)
css
.list-item {
position: absolute;
transform: translateY(calc(var(--offset) * var(--item-height)));
will-change: transform; /* 提示浏览器优化 */
}
.list-item {
position: absolute;
transform: translateY(calc(var(--offset) * var(--item-height)));
will-change: transform; /* 提示浏览器优化 */
}
- 节流滚动事件(Throttle) 原理:限制滚动事件触发频率,避免短时间内多次计算和渲染。 实现:
js
let isScrolling = false;
window.addEventListener('scroll', () => {
if (isScrolling) return;
isScrolling = true;
requestAnimationFrame(() => {
updateVisibleItems(); // 计算可视区域并更新元素
isScrolling = false;
});
}, 100); // 每 100ms 最多触发一次
let isScrolling = false;
window.addEventListener('scroll', () => {
if (isScrolling) return;
isScrolling = true;
requestAnimationFrame(() => {
updateVisibleItems(); // 计算可视区域并更新元素
isScrolling = false;
});
}, 100); // 每 100ms 最多触发一次
- 预加载与缓冲区(Buffer) 原理:在可视区域上下预加载少量元素,避免滚动时出现空白(白屏)或频繁触发新渲染。 实现:
js
const buffer = 5; // 预加载前后各 5 条数据
const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - buffer);
const endIndex = Math.min(totalCount, startIndex + visibleCount + buffer * 2);
const buffer = 5; // 预加载前后各 5 条数据
const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - buffer);
const endIndex = Math.min(totalCount, startIndex + visibleCount + buffer * 2);
- 使用 requestAnimationFrame 优化渲染 原理:将渲染逻辑合并到浏览器下一次重绘前执行,减少重复渲染。 实现:
js
let pendingScrollUpdate = null;
window.addEventListener('scroll', () => {
if (pendingScrollUpdate) return;
pendingScrollUpdate = requestAnimationFrame(() => {
updateVisibleItems();
pendingScrollUpdate = null;
});
});
let pendingScrollUpdate = null;
window.addEventListener('scroll', () => {
if (pendingScrollUpdate) return;
pendingScrollUpdate = requestAnimationFrame(() => {
updateVisibleItems();
pendingScrollUpdate = null;
});
});
- 启用硬件加速 原理:通过 CSS 属性触发 GPU 加速,减少主线程负担。 优化点:
css
.virtual-list {
transform: translateZ(0); /* 强制 GPU 加速 */
}
.list-item {
backface-visibility: hidden; /* 防止动画闪烁 */
}
.virtual-list {
transform: translateZ(0); /* 强制 GPU 加速 */
}
.list-item {
backface-visibility: hidden; /* 防止动画闪烁 */
}
大文件上传,单个文件去hash
WebSocket和SSE
TCP三次握手
web Worker返回大数据量的时候怎么优化
优化方向 | 具体措施 | 性能提升效果 |
---|---|---|
数据传输 | 使用 Transferable Objects | 减少内存复制开销 |
数据量 | 分块/流式传输 | 避免主线程阻塞 |
序列化 | 采用二进制格式(如 MessagePack) | 减少序列化时间 |
并行处理 | 多 Worker + 数据分片 | 提升计算并发度 |
内存管理 | 及时释放引用 | 防止内存泄漏 |
react事件和浏览器事件有什么区别(冒泡和捕获流程)
react17和react18的区别
- Concurrent Mode(并行模式)
- React 17: 引入了 Concurrent Mode 的概念,这是一个实验性功能,旨在提高应用的响应速度和渲染效率。它允许多个任务同时进行,从而减少主线程的阻塞。
- React 18: 将 Concurrent Mode 转为默认行为,并进行了多项改进,包括更好的内存管理和性能优化。开发者可以更轻松地利用并行渲染来提升用户体验。
- Performance Improvements(性能改进)
- React 17: 提供了一些初步的性能优化,特别是在组件渲染和状态更新方面。
- React 18: 进一步提升了性能,尤其是在处理大型应用时。React 18 引入了新的垃圾回收机制和更高效的渲染流程。
- Server Components(服务器组件)
- React 17: 引入了对服务器组件的支持,允许开发者在服务端渲染部分组件,从而减少客户端的负担。
- React 18: 进一步优化了服务器组件的支持,并增加了对自动卸载未使用的组件的功能。
- Error Boundaries(错误边界)
- React 17: 改进了错误边界的处理机制,使得在出现错误时能够更优雅地恢复组件。
- React 18: 继续优化错误边界,增加了对自定义错误边界的更多控制和更好的调试支持。
- New Features and Improvements(新功能和改进)
- React 17:
- 引入了 createRoot API,用于替代旧的 ReactDOM.render 方法。
- 改进了对 Context API 的支持。
- React 18:
- 提供了更好的 TypeScript 支持。
- 增加了对 Web Workers 的初步支持,允许在后台线程中运行 JavaScript,从而提升性能。
- Backwards Compatibility(向后兼容性)
- React 17: 向后兼容性良好,大部分代码可以直接从 React 16 升级到 React 17。
- React 18: 同样保持了良好的向后兼容性,但需要注意一些弃用的 API 和特性。
react hook用过哪些
useState、useEffect、useMemo、useCallback、useContext
跨端兼容性问题解决过哪些
说一下this指向
说一下事件循环
做一道事件循环的题目
js
console.log('script start')
async function fun1(){
await fun2()
console.log('async1')
}
async function fun2(){
console.log('async2')
}
fun1()
setTimeout(()=>{
console.log('setTimeout')
},0)
new Promise((resolve)=>{
console.log('promise1')
resolve()
}).then(()=>{
console.log('promise2')
}).then(()=>{
console.log('promise3')
})
console.log('script end')
console.log('script start')
async function fun1(){
await fun2()
console.log('async1')
}
async function fun2(){
console.log('async2')
}
fun1()
setTimeout(()=>{
console.log('setTimeout')
},0)
new Promise((resolve)=>{
console.log('promise1')
resolve()
}).then(()=>{
console.log('promise2')
}).then(()=>{
console.log('promise3')
})
console.log('script end')
script start async2 promise1 script end async1 promise2 promise3 setTimeout
说一下输出
js
var number = 5;
var foo = {
number: 3,
fn: (function () {
var number; // 块级作用域变量
this.number *= 2; // 修改全局number → 5 * 2=10
number = 3; // 局部变量赋值
return function () {
const num = number; // 获取闭包中的number(3)
console.log(num); // 第一次输出3
number *= 3; // 闭包number变为9
console.log(number); // 第二次输出9
};
})(),
};
const fn2 = foo.fn;
fn2.call(null); // 调用1 → 输出3,9
foo.fn(); // 调用2 → 输出9,27
console.log(window.number); // 最终输出10
var number = 5;
var foo = {
number: 3,
fn: (function () {
var number; // 块级作用域变量
this.number *= 2; // 修改全局number → 5 * 2=10
number = 3; // 局部变量赋值
return function () {
const num = number; // 获取闭包中的number(3)
console.log(num); // 第一次输出3
number *= 3; // 闭包number变为9
console.log(number); // 第二次输出9
};
})(),
};
const fn2 = foo.fn;
fn2.call(null); // 调用1 → 输出3,9
foo.fn(); // 调用2 → 输出9,27
console.log(window.number); // 最终输出10
括号的深度
输入:"(()(()))"
输出:3
js
var maxDepth = function (s) {
let ans = 0, size = 0;
for (let i = 0; i < s.length; ++i) {
const ch = s[i];
if (ch === '(') {
++size;
ans = Math.max(ans, size);
} else if (ch === ')') {
--size;
}
}
return ans;
};
var maxDepth = function (s) {
let ans = 0, size = 0;
for (let i = 0; i < s.length; ++i) {
const ch = s[i];
if (ch === '(') {
++size;
ans = Math.max(ans, size);
} else if (ch === ')') {
--size;
}
}
return ans;
};