跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScriptAI大前端算法

前端面试题详解:ES6、跨域、Vue 原理及性能优化

前端核心面试题,涵盖 ES6 新特性、跨域解决方案、Vue2 与 Vue3 响应式原理对比、浏览器渲染流程、网页加载优化策略(含虚拟列表与时间切片)、JavaScript 基础机制(闭包、事件循环、new 关键字)以及 TypeScript 装饰器应用。内容旨在帮助开发者系统复习前端知识体系,提升面试通过率。

ApiHolic发布于 2026/4/6更新于 2026/5/1924 浏览

前端面试题详细解答

1. ES6 新特性详解(重要 10 个)

核心特性
// 1. let 和 const - 块级作用域
let x = 10; // 可重新赋值
const y = 20; // 不可重新赋值,但对象属性可修改

// 2. 箭头函数
const add = (a, b) => a + b;
// 特点:没有自己的 this,继承父级 this;不能作为构造函数

// 3. 模板字符串
const name = "John";
const greeting = `Hello, ${name}!`;
// 支持多行字符串

// 4. 解构赋值
const [a, b] = [1, 2]; // 数组解构
const {name, age} = {name: "John", age: 25}; // 对象解构

// 5. 默认参数
function greet(name = "Guest") {
    return `Hello, ${name}`;
}

// 6. 扩展运算符
const arr1 = [1, 2];
const arr2 = [...arr1, 3, 4]; // [1, 2, 3, 4]
const obj1 = {a: };
 obj2 = {...obj1, : }; 


 x = , y = ;
 point = {x, y}; 


 promise =  ( {
    ( (), );
});


  () {
     data =  promise;
     data;
}


  {
    () {
        . = name;
    }
    () {
         ;
    }
     () {
          (name);
    }
}
1
const
b
2
// {a: 1, b: 2}
// 7. 对象简写
const
10
20
const
// 等同于 {x: x, y: y}
// 8. Promise
const
new
Promise
(resolve, reject) =>
setTimeout
() =>
resolve
"Done"
1000
// 9. async/await(ES8,但通常归为 ES6+)
async
function
fetchData
const
await
return
// 10. 类(Class)
class
Person
constructor
name
this
name
greet
return
`Hello, I'm ${this.name}`
static
create
name
return
new
Person
其他重要特性
  • 模块化:import/export
  • Symbol:唯一标识符
  • Set/Map:新的数据结构
  • for…of 循环:遍历可迭代对象
  • 生成器函数:function*
  • Proxy/Reflect:元编程
  • 可选链操作符:?.(ES2020)
  • 空值合并运算符:??(ES2020)

2. 什么是跨域

同源策略
// 同源条件:协议、域名、端口必须完全相同
// http://example.com:80 ≠ https://example.com:80 (协议不同)
// http://example.com:80 ≠ http://api.example.com:80 (域名不同)
// http://example.com:80 ≠ http://example.com:8080 (端口不同)
跨域解决方案
1. CORS(跨域资源共享)
// 服务器设置响应头
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
res.setHeader('Access-Control-Allow-Credentials', 'true'); // 允许携带 cookie

// 简单请求 vs 预检请求
// 简单请求:GET/HEAD/POST,Content-Type 为特定值
// 预检请求:非简单请求前会发送 OPTIONS 请求
2. JSONP
// 客户端
function handleResponse(data) {
    console.log(data);
}

// 动态创建 script 标签
const script = document.createElement('script');
script.src = 'http://api.example.com/data?callback=handleResponse';
document.body.appendChild(script);

// 服务器响应
// handleResponse({data: "some data"});
3. 代理服务器
// 开发环境代理(webpack 配置)
module.exports = {
    devServer: {
        proxy: {
            '/api': {
                target: 'http://api.example.com',
                changeOrigin: true,
                pathRewrite: {'^/api': ''}
            }
        }
    }
};
4. WebSocket
// WebSocket 不受同源策略限制
const socket = new WebSocket('ws://api.example.com');
5. Nginx 反向代理
# nginx 配置
location /api/ {
    proxy_pass http://api.example.com/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

3. 监听数组变化

Vue2 的实现原理
// 1. 重写数组方法
const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);
const methodsToPatch = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'];
methodsToPatch.forEach(function(method) {
    const original = arrayProto[method];
    Object.defineProperty(arrayMethods, method, {
        value: function(...args) {
            const result = original.apply(this, args);
            const ob = this.__ob__; // 获取新增的元素
            let inserted;
            switch(method) {
                case 'push':
                case 'unshift': inserted = args; break;
                case 'splice': inserted = args.slice(2); break;
            }
            // 对新增元素进行响应式处理
            if(inserted) ob.observeArray(inserted);
            // 通知依赖更新
            ob.dep.notify();
            return result;
        },
        enumerable: false,
        writable: true,
        configurable: true
    });
});

// 2. 替换数组的原型
const arr = [1, 2, 3];
Object.setPrototypeOf(arr, arrayMethods);
Vue3 的实现原理
// 使用 Proxy 代理整个数组
function reactiveArray(arr) {
    return new Proxy(arr, {
        get(target, key) {
            // 处理数组的特殊情况
            if(key === 'length') return target.length;
            const value = target[key];
            // 如果访问的是方法,绑定正确的 this
            if(typeof value === 'function') {
                return value.bind(target);
            }
            return value;
        },
        set(target, key, value, receiver) {
            const oldValue = target[key];
            // 设置属性值
            const result = Reflect.set(target, key, value, receiver);
            // 判断是新增还是修改
            const type = Number(key) < target.length ? 'SET' : 'ADD';
            // 触发更新
            if(type === 'ADD' || oldValue !== value) {
                trigger(target, key, type);
            }
            return result;
        }
    });
}

4. v-if vs v-show

原理对比
<template>
    <!-- v-if:条件渲染 -->
    <div v-if="show">使用 v-if</div>
    <!-- v-show:条件显示 -->
    <div v-show="show">使用 v-show</div>
</template>
<script>
export default {
    data() {
        return {
            show: true
        };
    }
};
</script>
差异对比表
特性v-ifv-show
DOM 操作条件为 false 时,元素从 DOM 移除元素始终在 DOM 中,只切换 display 属性
编译/卸载切换时触发组件的生命周期钩子不触发生命周期钩子
性能初始渲染开销小,切换开销大初始渲染开销大,切换开销小
使用场景不频繁切换,条件很少改变频繁切换,需要保持状态
配合使用可与 v-else、v-else-if 配合没有配套指令
源码分析
// v-if 的编译结果
function render() {
    return show ? createElement('div', 'v-if 内容') : createEmptyVNode();
}

// v-show 的编译结果
function render() {
    return createElement('div', {
        directives: [{name: 'show', value: show}],
        style: {display: show ? '' : 'none'}
    }, 'v-show 内容');
}

5. 网页加载优化

性能指标(Core Web Vitals)
  1. LCP(最大内容绘制) < 2.5 秒
  2. FID(首次输入延迟) < 100 毫秒
  3. CLS(累计布局偏移) < 0.1
优化策略
1. 代码优化
// 代码分割
const LazyComponent = () => import('./LazyComponent.vue');

// 路由懒加载
const routes = [
    {path: '/home', component: () => import('./views/Home.vue')}
];

// Webpack 配置优化
module.exports = {
    optimization: {
        splitChunks: {
            chunks: 'all', // 代码分割
            cacheGroups: {
                vendor: {
                    test: /[\/]node_modules[\/]/,
                    name: 'vendors'
                }
            }
        }
    }
};
2. 资源优化
<!-- 图片优化 -->
<img src="image.jpg" 
     srcset="image-320w.jpg 320w, image-480w.jpg 480w" 
     sizes="(max-width: 600px) 480px, 800px" 
     loading="lazy" <!-- 懒加载 --> 
     alt="描述文本">

<!-- 预加载关键资源 -->
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="critical.css" as="style">
<link rel="prefetch" href="next-page.html"> <!-- 预取 -->
3. 缓存策略
// Service Worker 缓存
self.addEventListener('install', event => {
    event.waitUntil(
        caches.open('v1').then(cache => {
            return cache.addAll(['/', '/styles/main.css', '/script/main.js']);
        })
    );
});
4. 使用 Lighthouse 分析
# 命令行使用
npx lighthouse https://example.com --view
# 生成报告
npx lighthouse https://example.com --output=json --output-path=report.json

6. 浏览器渲染过程

详细流程
1. 构建 DOM 树
// HTML → DOM 树
// <html> → DOM 节点
// <body> → DOM 节点
// <div> → DOM 节点
2. 构建 CSSOM 树
/* CSS → CSSOM 树 */
body { font-size: 16px; }
div { color: red; }
3. 渲染树构建
  • 结合 DOM 和 CSSOM
  • 排除不可见元素(display: none)
4. 布局(重排)
// 计算每个元素的位置和大小
// 触发重排的操作:
element.style.width = '100px';
element.style.height = '200px';
window.getComputedStyle(element);
5. 绘制(重绘)
// 填充像素
// 触发重绘的操作:
element.style.color = 'red';
element.style.backgroundColor = '#fff';
6. 合成
// GPU 加速的图层合成
element.style.transform = 'translateX(100px)'; // 触发合成层
优化建议
// 避免强制同步布局
function badExample() {
    // 读取 → 写入 → 读取 → 写入
    const width = element.offsetWidth; // 触发重排
    element.style.width = width + 10 + 'px'; // 触发重排
}

function goodExample() {
    // 读取 → 读取 → 写入 → 写入
    const width = element.offsetWidth;
    const height = element.offsetHeight;
    element.style.width = width + 10 + 'px';
    element.style.height = height + 10 + 'px';
}

7. 节流和防抖

防抖(Debounce)
// 原理:在事件被触发 n 秒后再执行,如果在这 n 秒内又被触发,则重新计时
function debounce(fn, delay) {
    let timer = null;
    return function(...args) {
        const context = this;
        // 清除之前的定时器
        clearTimeout(timer);
        // 设置新的定时器
        timer = setTimeout(() => {
            fn.apply(context, args);
        }, delay);
    };
}

// 使用场景:搜索框输入、窗口 resize
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', debounce(function() {
    console.log('搜索:', this.value);
}, 500));
节流(Throttle)
// 原理:规定在一个单位时间内,只能触发一次函数

// 时间戳实现
function throttle(fn, delay) {
    let lastTime = 0;
    return function(...args) {
        const now = Date.now();
        const context = this;
        if(now - lastTime >= delay) {
            fn.apply(context, args);
            lastTime = now;
        }
    };
}

// 定时器实现
function throttle(fn, delay) {
    let timer = null;
    let lastArgs = null;
    return function(...args) {
        lastArgs = args;
        if(!timer) {
            timer = setTimeout(() => {
                fn.apply(this, lastArgs);
                timer = null;
            }, delay);
        }
    };
}

// 使用场景:滚动加载、按钮点击
window.addEventListener('scroll', throttle(function() {
    console.log('滚动位置:', window.scrollY);
}, 100));
结合版(加强版节流)
function enhancedThrottle(fn, delay, options = {}) {
    const { leading = true, trailing = true } = options;
    let timer = null;
    let lastTime = 0;
    let lastArgs = null;
    return function(...args) {
        const context = this;
        const now = Date.now();
        // 计算剩余时间
        const remaining = delay - (now - lastTime);
        // 更新参数
        lastArgs = args;
        if(remaining <= 0) {
            // 时间到了,执行函数
            if(timer) {
                clearTimeout(timer);
                timer = null;
            }
            if(leading) {
                fn.apply(context, args);
            }
            lastTime = now;
        } else if(!timer && trailing) {
            // 设置定时器,确保最后一次执行
            timer = setTimeout(() => {
                fn.apply(context, lastArgs);
                timer = null;
                lastTime = Date.now();
            }, remaining);
        }
    };
}

8. 闭包

基本概念
// 闭包:能够访问其他函数作用域中变量的函数
function outer() {
    const name = "John"; // 局部变量
    function inner() {
        console.log(name); // 访问外部函数的变量
    }
    return inner; // 返回内部函数
}
const closureFn = outer();
closureFn(); // "John"
实际应用
1. 数据私有化
function createCounter() {
    let count = 0; // 私有变量
    return {
        increment() { count++; return count; },
        decrement() { count--; return count; },
        getCount() { return count; }
    };
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.getCount()); // 2
2. 函数工厂
function createMultiplier(multiplier) {
    return function(x) {
        return x * multiplier;
    };
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
3. 模块模式
const myModule = (function() {
    let privateVar = 0;
    function privateMethod() { return privateVar; }
    return {
        publicMethod() {
            privateVar++;
            return privateMethod();
        }
    };
})();
console.log(myModule.publicMethod()); // 1
内存管理
// 闭包可能导致内存泄漏
function leakMemory() {
    const largeArray = new Array(1000000).fill('data');
    return function() {
        console.log('仍然持有 largeArray 的引用'); // largeArray 不会被垃圾回收
    };
}

// 解决方案:及时释放引用
function noLeak() {
    let largeArray = new Array(1000000).fill('data');
    const result = largeArray.length; // 使用完后设为 null
    largeArray = null;
    return function() {
        console.log('不持有 largeArray 的引用');
        return result;
    };
}

9. 浏览器线程

主要线程
1. 主线程(UI 线程)
// 负责:DOM 渲染、JavaScript 执行、用户交互
// 注意:JavaScript 是单线程的
console.log(1);
setTimeout(() => console.log(2), 0);
console.log(3);
// 输出:1, 3, 2(因为有事件循环)
2. 浏览器内核线程
  • GUI 渲染线程:解析 HTML/CSS,构建 DOM 树
  • JavaScript 引擎线程:执行 JavaScript 代码
  • 事件触发线程:管理事件队列
  • 定时器触发线程:setTimeout/setInterval
  • 异步 HTTP 请求线程:XMLHttpRequest
事件循环机制
// 微任务(Microtask)vs 宏任务(Macrotask)
console.log('script start'); // 同步任务
setTimeout(() => {
    console.log('setTimeout'); // 宏任务
}, 0);
Promise.resolve().then(() => {
    console.log('promise1'); // 微任务
}).then(() => {
    console.log('promise2'); // 微任务
});
console.log('script end');

// 执行顺序:
// 1. script start
// 2. script end
// 3. promise1
// 4. promise2
// 5. setTimeout
Web Workers
// 主线程
const worker = new Worker('worker.js');
worker.postMessage({data: 'Hello'});
worker.onmessage = function(event) {
    console.log('收到 worker 消息:', event.data);
};

// worker.js(另一个线程)
// self.onmessage = function(event) {
//     const result = heavyComputation(event.data);
//     self.postMessage(result);
// };
// function heavyComputation(data) {
//     // 耗时操作
//     return data.toUpperCase();
// }

10. Vue3 vs Vue2 区别

核心差异对比表
特性Vue2Vue3
响应式原理Object.definePropertyProxy
Composition APIOptions APIComposition API + Options API
性能较慢更快(打包体积小 40%)
TypeScript 支持一般完善
Fragment不支持支持多根节点
Teleport不支持支持
Suspense不支持支持
Tree-shaking有限更好的支持
响应式系统
// Vue2 响应式
const data = {count: 0};
Object.defineProperty(data, 'count', {
    get() { console.log('获取 count'); return value; },
    set(newValue) { console.log('设置 count'); value = newValue; }
});

// Vue3 响应式
const data = {count: 0};
const proxy = new Proxy(data, {
    get(target, key) {
        console.log(`获取${key}`);
        return target[key];
    },
    set(target, key, value) {
        console.log(`设置${key}`);
        target[key] = value;
        return true;
    }
});
Composition API 示例
<template>
    <div>
        <p>Count: {{ count }}</p>
        <p>Double: {{ doubleCount }}</p>
        <button @click="increment">Increment</button>
    </div>
</template>
<script>
import { ref, computed, onMounted } from 'vue';
export default {
    setup() {
        // 响应式数据
        const count = ref(0);
        // 计算属性
        const doubleCount = computed(() => count.value * 2);
        // 方法
        function increment() {
            count.value++;
        }
        // 生命周期
        onMounted(() => {
            console.log('组件已挂载');
        });
        return { count, doubleCount, increment };
    }
};
</script>
性能优化
// Vue3 的静态提升
const _hoisted_1 = {id: "app"};
// 静态节点提升
const _hoisted_2 = /*#__PURE__*/createVNode("div", null, "静态内容");

// Vue3 的 Patch Flag
const vnode = {
    type: 'div',
    props: {id: 'app', class: 'container'},
    children: [{
        type: 'span',
        children: '动态内容',
        patchFlag: 1 /* TEXT */
    }]
};

11. new 关键字

实现原理
// new 关键字的作用
function Person(name) {
    this.name = name;
}
const john = new Person('John');

// 模拟 new 的实现
function myNew(constructor, ...args) {
    // 1. 创建一个空对象
    const obj = {};
    // 2. 将对象的原型指向构造函数的 prototype
    Object.setPrototypeOf(obj, constructor.prototype);
    // 3. 将构造函数的 this 绑定到新对象
    const result = constructor.apply(obj, args);
    // 4. 如果构造函数返回对象,则返回该对象,否则返回新对象
    return result instanceof Object ? result : obj;
}
const john2 = myNew(Person, 'John');
详细步骤分析
function Animal(name) {
    this.name = name;
    this.speak = function() {
        return `${this.name} makes a noise`;
    };
    // 如果构造函数返回一个对象,new 表达式会返回这个对象
    // return { custom: 'object' };
}
Animal.prototype.eat = function() {
    return `${this.name} eats food`;
};

// 使用 new
const animal = new Animal('Dog');

// 等同于
// const animal = {};
// animal.__proto__ = Animal.prototype;
// Animal.call(animal, 'Dog');

12. bind、call、apply 的区别

基本用法对比
const person = {name: 'John', greet: function(greeting, punctuation) {
    return `${greeting}, ${this.name}${punctuation}`;
}};
const anotherPerson = {name: 'Jane'};

// call:立即调用,参数逐个传递
person.greet.call(anotherPerson, 'Hello', '!'); // "Hello, Jane!"

// apply:立即调用,参数数组传递
person.greet.apply(anotherPerson, ['Hi', '!!']); // "Hi, Jane!!"

// bind:返回新函数,不立即调用
const boundGreet = person.greet.bind(anotherPerson, 'Hey');
boundGreet('?'); // "Hey, Jane?"
手写实现
// 实现 call
Function.prototype.myCall = function(context, ...args) {
    // 如果 context 是 null 或 undefined,指向全局对象
    context = context || window;
    // 创建唯一 key,避免属性冲突
    const fnKey = Symbol('fn');
    // 将函数作为 context 的方法
    context[fnKey] = this;
    // 执行函数
    const result = context[fnKey](...args);
    // 删除添加的方法
    delete context[fnKey];
    return result;
};

// 实现 apply
Function.prototype.myApply = function(context, argsArray = []) {
    context = context || window;
    const fnKey = Symbol('fn');
    context[fnKey] = this;
    const result = context[fnKey](...argsArray);
    delete context[fnKey];
    return result;
};

// 实现 bind
Function.prototype.myBind = function(context, ...bindArgs) {
    const originalFn = this;
    return function boundFn(...callArgs) {
        // 判断是否作为构造函数调用(使用 new)
        const isConstructorCall = new.target !== undefined;
        if(isConstructorCall) {
            // 如果是 new 调用,忽略绑定的 this
            return new originalFn(...bindArgs, ...callArgs);
        } else {
            // 普通调用,使用绑定的 this
            return originalFn.apply(context, [...bindArgs, ...callArgs]);
        }
    };
};
实际应用场景
// 1. 借用数组方法处理类数组对象
function sum() {
    // arguments 是类数组,没有数组方法
    const args = Array.prototype.slice.call(arguments);
    return args.reduce((acc, val) => acc + val, 0);
}

// 2. 构造函数继承
function Parent(name) {
    this.name = name;
}
function Child(name, age) {
    Parent.call(this, name); // 继承属性
    this.age = age;
}

// 3. 事件处理函数绑定 this
class Button {
    constructor() {
        this.text = 'Click me';
        // 使用 bind 保持 this 指向
        this.handleClick = this.handleClick.bind(this);
    }
    handleClick() {
        console.log(this.text);
    }
}

13. TypeScript 装饰器

装饰器类型
// 类装饰器
function ClassDecorator(constructor: Function) {
    console.log('类装饰器执行');
    constructor.prototype.newProperty = 'added by decorator';
}

// 方法装饰器
function MethodDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log(`方法装饰器:${propertyKey}`);
    const originalMethod = descriptor.value;
    descriptor.value = function(...args: any[]) {
        console.log(`调用方法:${propertyKey}`);
        return originalMethod.apply(this, args);
    };
}

// 属性装饰器
function PropertyDecorator(target: any, propertyKey: string) {
    console.log(`属性装饰器:${propertyKey}`);
}

// 参数装饰器
function ParameterDecorator(target: any, propertyKey: string, parameterIndex: number) {
    console.log(`参数装饰器:${propertyKey}的第${parameterIndex}个参数`);
}

// 访问器装饰器
function AccessorDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log(`访问器装饰器:${propertyKey}`);
}

// 装饰器工厂
function LogDecorator(message: string) {
    return function(target: any, propertyKey: string, descriptor?: PropertyDescriptor) {
        console.log(`${message}: ${propertyKey}`);
    };
}
实际应用示例
// 1. 日志装饰器
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function(...args: any[]) {
        console.log(`调用 ${propertyKey},参数:`, args);
        const result = originalMethod.apply(this, args);
        console.log(`返回结果:`, result);
        return result;
    };
}

// 2. 自动绑定 this 装饰器
function autobind(_target: any, _propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    const adjustedDescriptor: PropertyDescriptor = {
        configurable: true,
        enumerable: false,
        get() {
            // 返回绑定 this 的方法
            return originalMethod.bind(this);
        }
    };
    return adjustedDescriptor;
}

// 3. 验证装饰器
function validate(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function(...args: any[]) {
        // 参数验证逻辑
        args.forEach((arg, index) => {
            if(arg === undefined || arg === null) {
                throw new Error(`参数 ${index} 不能为空`);
            }
        });
        return originalMethod.apply(this, args);
    };
}

// 使用示例
class UserService {
    private users: string[] = [];
    
    @log
    @validate
    addUser(@ParameterDecorator name: string) {
        this.users.push(name);
        return this.users;
    }
    
    @autobind
    getUsers() {
        return this.users;
    }
}

14. 10w 数据展示优化

虚拟列表实现
<template>
    <div ref="container" @scroll="handleScroll" class="virtual-list-container">
        <!-- 撑开容器,显示滚动条 -->
        <div :style="{ height: totalHeight + 'px' }" class="virtual-list-phantom"></div>
        <!-- 可视区域内容 -->
        <div :style="{ transform: `translateY(${offset}px)` }" class="virtual-list-content">
            <div v-for="item in visibleData" :key="item.id" :style="{ height: itemHeight + 'px' }" class="virtual-list-item">
                {{ item.content }}
            </div>
        </div>
    </div>
</template>
<script>
export default {
    props: {
        data: { type: Array, required: true },
        itemHeight: { type: Number, default: 50 },
        buffer: { type: Number, default: 5 }
    },
    data() {
        return {
            startIndex: 0, // 开始索引
            endIndex: 0, // 结束索引
            offset: 0 // 偏移量
        };
    },
    computed: {
        // 总高度
        totalHeight() {
            return this.data.length * this.itemHeight;
        },
        // 容器高度
        containerHeight() {
            return this.$refs.container?.clientHeight || 0;
        },
        // 可见区域项数
        visibleCount() {
            return Math.ceil(this.containerHeight / this.itemHeight);
        },
        // 实际渲染的数据
        visibleData() {
            const start = Math.max(0, this.startIndex - this.buffer);
            const end = Math.min(this.data.length, this.endIndex + this.buffer);
            return this.data.slice(start, end);
        }
    },
    mounted() {
        this.updateVisibleData();
    },
    methods: {
        handleScroll() {
            const scrollTop = this.$refs.container.scrollTop;
            // 计算开始索引
            this.startIndex = Math.floor(scrollTop / this.itemHeight);
            // 计算结束索引
            this.endIndex = Math.min(
                this.data.length,
                this.startIndex + this.visibleCount
            );
            // 计算偏移量
            this.offset = this.startIndex * this.itemHeight;
        },
        updateVisibleData() {
            this.startIndex = 0;
            this.endIndex = Math.min(this.data.length, this.visibleCount);
        }
    }
};
</script>
<style>
.virtual-list-container {
    height: 500px;
    overflow-y: auto;
    position: relative;
}
.virtual-list-phantom {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    z-index: -1;
}
.virtual-list-content {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
}
.virtual-list-item {
    display: flex;
    align-items: center;
    padding: 0 16px;
    box-sizing: border-box;
    border-bottom: 1px solid #eee;
}
</style>
时间分片渲染
// 使用 requestAnimationFrame 分批渲染
function renderLargeData(data, container, chunkSize = 100) {
    let index = 0;
    function renderChunk() {
        const fragment = document.createDocumentFragment();
        for(let i = 0; i < chunkSize && index < data.length; i++, index++) {
            const item = document.createElement('div');
            item.textContent = data[index];
            fragment.appendChild(item);
        }
        container.appendChild(fragment);
        // 如果还有数据,继续渲染下一批
        if(index < data.length) {
            requestAnimationFrame(renderChunk);
        }
    }
    renderChunk();
}

// 使用 Web Worker 处理数据
const worker = new Worker('data-processor.js');
worker.postMessage({action: 'process', data: largeData});
worker.onmessage = function(event) {
    const processedData = event.data;
    // 在主线程渲染处理后的数据
};

15. 时间切片

基本原理
// 使用 requestIdleCallback 实现时间切片
function timeSlicingWork(unitsOfWork) {
    let currentIndex = 0;
    function doWork(deadline) {
        // 在空闲时间内执行工作单元
        while(currentIndex < unitsOfWork.length && deadline.timeRemaining() > 0) {
            performUnitOfWork(unitsOfWork[currentIndex]);
            currentIndex++;
        }
        // 如果还有工作,继续调度
        if(currentIndex < unitsOfWork.length) {
            requestIdleCallback(doWork);
        } else {
            console.log('所有工作完成');
        }
    }
    requestIdleCallback(doWork);
}

// React 中的时间切片实现(简化版)
function workLoop(deadline) {
    let shouldYield = false;
    while(nextUnitOfWork && !shouldYield) {
        // 执行工作单元
        nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
        // 检查是否需要让出控制权
        shouldYield = deadline.timeRemaining() < 1;
    }
    // 如果还有工作,继续调度
    if(nextUnitOfWork) {
        requestIdleCallback(workLoop);
    }
}
requestIdleCallback(workLoop);
实际应用示例
// 1. 大数据处理
function processBigData(data, processItem, chunkSize = 100) {
    return new Promise((resolve) => {
        let index = 0;
        const results = [];
        function processChunk(deadline) {
            while(index < data.length && deadline.timeRemaining() > 0) {
                const chunk = data.slice(index, index + chunkSize);
                // 处理数据块
                for(const item of chunk) {
                    results.push(processItem(item));
                }
                index += chunkSize;
                // 更新进度
                updateProgress((index / data.length) * 100);
            }
            if(index < data.length) {
                // 还有数据,继续处理
                requestIdleCallback(processChunk);
            } else {
                // 处理完成
                resolve(results);
            }
        }
        requestIdleCallback(processChunk);
    });
}

// 2. 长列表渲染优化
class VirtualScroller {
    constructor(container, items, renderItem) {
        this.container = container;
        this.items = items;
        this.renderItem = renderItem;
        this.renderedItems = new Set();
    }
    renderVisibleItems() {
        const visibleRange = this.getVisibleRange();
        const itemsToRender = [];
        for(let i = visibleRange.start; i < visibleRange.end; i++) {
            if(!this.renderedItems.has(i)) {
                itemsToRender.push(i);
            }
        }
        // 使用时间切片分批渲染
        this.renderWithTimeSlice(itemsToRender);
    }
    renderWithTimeSlice(itemIndices) {
        let index = 0;
        const renderBatch = (deadline) => {
            while(index < itemIndices.length && deadline.timeRemaining() > 0) {
                const itemIndex = itemIndices[index];
                const item = this.items[itemIndex];
                // 渲染单个项目
                const element = this.renderItem(item, itemIndex);
                this.container.appendChild(element);
                this.renderedItems.add(itemIndex);
                index++;
            }
            if(index < itemIndices.length) {
                requestIdleCallback(renderBatch);
            }
        };
        requestIdleCallback(renderBatch);
    }
}
React Concurrent Mode 中的时间切片
// React 18+ 中的并发特性
import { startTransition, useDeferredValue } from 'react';

function SearchResults({ query }) {
    const deferredQuery = useDeferredValue(query);
    return (
        <div>
            <SlowList query={deferredQuery}/>
        </div>
    );
}

// 在事件处理中使用 startTransition
function handleChange(e) {
    setInput(e.target.value);
    // 将 setQuery 标记为过渡更新
    startTransition(() => {
        setQuery(e.target.value);
    });
}

// 这会告诉 React 这个更新不是紧急的,可以被中断

目录

  1. 前端面试题详细解答
  2. 1. ES6 新特性详解(重要 10 个)
  3. 核心特性
  4. 其他重要特性
  5. 2. 什么是跨域
  6. 同源策略
  7. 跨域解决方案
  8. 1. CORS(跨域资源共享)
  9. 2. JSONP
  10. 3. 代理服务器
  11. 4. WebSocket
  12. 5. Nginx 反向代理
  13. nginx 配置
  14. 3. 监听数组变化
  15. Vue2 的实现原理
  16. Vue3 的实现原理
  17. 4. v-if vs v-show
  18. 原理对比
  19. 差异对比表
  20. 源码分析
  21. 5. 网页加载优化
  22. 性能指标(Core Web Vitals)
  23. 优化策略
  24. 1. 代码优化
  25. 2. 资源优化
  26. 3. 缓存策略
  27. 4. 使用 Lighthouse 分析
  28. 命令行使用
  29. 生成报告
  30. 6. 浏览器渲染过程
  31. 详细流程
  32. 1. 构建 DOM 树
  33. 2. 构建 CSSOM 树
  34. 3. 渲染树构建
  35. 4. 布局(重排)
  36. 5. 绘制(重绘)
  37. 6. 合成
  38. 优化建议
  39. 7. 节流和防抖
  40. 防抖(Debounce)
  41. 节流(Throttle)
  42. 结合版(加强版节流)
  43. 8. 闭包
  44. 基本概念
  45. 实际应用
  46. 1. 数据私有化
  47. 2. 函数工厂
  48. 3. 模块模式
  49. 内存管理
  50. 9. 浏览器线程
  51. 主要线程
  52. 1. 主线程(UI 线程)
  53. 2. 浏览器内核线程
  54. 事件循环机制
  55. Web Workers
  56. 10. Vue3 vs Vue2 区别
  57. 核心差异对比表
  58. 响应式系统
  59. Composition API 示例
  60. 性能优化
  61. 11. new 关键字
  62. 实现原理
  63. 详细步骤分析
  64. 12. bind、call、apply 的区别
  65. 基本用法对比
  66. 手写实现
  67. 实际应用场景
  68. 13. TypeScript 装饰器
  69. 装饰器类型
  70. 实际应用示例
  71. 14. 10w 数据展示优化
  72. 虚拟列表实现
  73. 时间分片渲染
  74. 15. 时间切片
  75. 基本原理
  76. 实际应用示例
  77. React Concurrent Mode 中的时间切片
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • DFS/BFS 专项练习:从海岛问题到图论基础应用 (C/C++)
  • 如何训练一个“万亿大模型”?
  • Triton 异步推理深度解析:C++ 客户端高性能并发处理实战
  • Java 三大集合详解:List、Set、Map
  • Android 高效网络语音通话:WebRTC 与 Socket.IO 实战优化
  • Halcon 基础面试题:图像数据类型与尺寸表示
  • Docker 部署 OpenClaw:智谱 AI 本地执行引擎集成指南
  • 本地大模型部署:从入门到弃坑的现实复盘
  • 负载均衡常见算法解析与 Dubbo 实践
  • 本地 AI 小说生成器部署指南:从零搭建与配置
  • Quartus 18.0 安装及 ModelSim 环境配置
  • Trae 集成腾讯地图 MCP 实战:AI 直接调用地理信息服务
  • Diffusion Transformer (DiT):从图像生成到机器人动作预测的架构演进
  • MCP Server 商店:AI 即插即用与工具自动化实战
  • C++ string 常用函数详解(三)
  • 数据结构:B-树原理与实现
  • C++ 使用 etcd-cpp-apiv3 搭建服务注册发现中心
  • AI 编程工具选型指南:Copilot、Trae 等主流方案深度解析
  • Python 新手必备的 5 个编程练习网站指南
  • 初识 AI 大语言模型:概念、原理与能力

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online