Published on

前端面试系列一

Authors
  • avatar
    Name
    Tszkong Cheng
    Twitter

一、请绘制一张九九乘法表

九九乘法表

解法

<div id="wrapper"></div>
<script>
    const table = document.getElementById('wrapper');
    for (let i = 1; i < 9; i++) {
        const row = document.createElement('div');
        for (let j = 1; j <= i; j++) {
            const cell = document.createElement('span')
            cell.innerHTML = `${i} x ${j} = ${i * j}`
            row.appendChild(cell)
        }
        table.appendChild(row)
    }
    document.body.appendChild(table)
</script>

二、请说一下对宏任务、微任务、事件循环的了解

1. 事件循环(Event Loop)

JavaScript 是单线程语言,为了能同时处理异步任务,引入了事件循环机制。 事件循环的核心逻辑是:

不断从任务队列中取出任务,放入主线程执行。

主要流程如下:

  1. 执行主线程中的同步任务(Script 脚本)。
  2. 执行完后,开始进入事件循环。
  3. 检查是否有微任务队列(Microtask Queue)中的任务,有则全部执行。
  4. 然后从宏任务队列(Macrotask Queue)中取出一个任务执行。
  5. 重复步骤 3~4,直到宏任务队列为空。

2. 宏任务(Macrotask)

宏任务(Macrotask)指的都是执行环境为浏览器的异步任务,比如:

  • setTimeout
  • setInterval
  • setImmediate(Node.js)
  • I/O
  • requestAnimationFrame

3. 微任务(Microtask)

微任务(Microtask)指的都是执行环境为 Promise 的异步任务,比如:

  • Promise.then / catch / finally
  • queueMicrotask(原生 API)

4. 举例子说明执行顺序

console.log('1');

setTimeout(() => {
  console.log('2');
  Promise.resolve().then(() => {
    console.log('3');
  });
}, 0);

Promise.resolve().then(() => {
  console.log('4');
  setTimeout(() => {
    console.log('5');
  }, 0);
}).then(() => {
    console.log('6');
})

setTimeout(() => {
  console.log('7');
}, 0);

console.log('8');

执行顺序为: 1 8 4 6 2 3 7 5

三、回流(Reflow)、重绘(Rapaint)、重排(Layout)

回流/重排是同一概念,叫法不同。含义是:当页面中的元素尺寸、位置或结构发生变化,浏览器会重新计算元素的几何属性(位置、宽高等)。

触发时机:

  • 添加或者删除 DOM 元素;
  • 改变元素的位置;
  • 改变元素的尺寸大小;
  • 改变字体大小;
  • 改变元素的显示状态(display: none / block)。

性能消耗: ⚠️ 回流开销较大,可能影响整个 DOM 树或其一部分。

重绘:当元素的样式发生改变,但没有影响布局(几何形状),只需要重新渲染外观样式时,会发生重绘。

触发时机:

  • 改变元素颜色;
  • 改变元素阴影;
  • 边框样式等。

性能消耗: ✅ 重绘开销较小,但频繁发生也会影响性能。

关系对比

项目回流重绘
影响内容结构、样式样式(不影响结构)
触发时机改变元素位置、尺寸、结构、样式改变元素颜色、阴影、边框样式等
性能消耗
是否会引发通常会引发重绘不引发回流

如何避免或减少回流重绘:

  • 避免或减少 DOM 操作次数;
  • 避免逐条修改样式,使用 class 切换/设置 style;
  • 隐藏元素再操作,隐藏元素不参与回流,等于“离线处理”;
  • 使用虚拟 DOM或合适的框架;
  • 动画中避免使用 top/left/width/height 等属性,使用 transform 和 opacity。

四、请说下 Vue 响应式

1. Vue 2 与 Vue 3 响应式实现原理对比

特性Vue 2Vue 3
实现方式Object.definePropertyProxy
支持的数据类型仅对象、数组(不支持 Map/Set)所有对象类型(含 Map、Set 等)
动态属性手动 Vue.set() 添加响应式自动响应
数组变异监听依靠重写原型方法(push 等)Proxy 直接拦截
嵌套对象仅支持第一层支持任意层
深层嵌套响应初始化时递归遍历每个属性按需惰性代理,性能更优
依赖追踪方式使用 Watcher + Dep使用 effect + reactiveMap
性能初始化慢,依赖管理复杂响应性更快、更灵活
缺陷

2. Vue 2 的主要缺陷

  1. 无法监听新增/删除属性;
  2. 数组索引和 length 无法被响应式监听;
  3. 初始化时递归遍历所有属性,性能差;
  4. 对象解构会失去响应式。
前端面试系列一 | Chengtszkong's Blog