Skip to content

两道代码题

面试题1

完成 Component 类代码的书写,要求:

  1. 修改数据时能够触发 render 方法的执行
  2. 同步变更时需要合并,仅触发一次 render 方法
js
class Component {
  data = {
    name: "",
  };
  constructor() {
  }
  render() {
    console.log(`render - name: ${this.data.name}`);
  }
}

const com = new Component();
// 要求以下代码需要触发 render 方法,并且同步变更需要合并
com.data.name = "张三";
com.data.name = "李四";
com.data.name = "王五";

setTimeout(() => {
  com.data.name = "渡一";
}, 0);

面试题2

以下两段代码在 Vue 中分别渲染几次?为什么?

代码一:

vue
<template>
	<div>{{rCount}}</div>
</template>
<script setup>
import { ref } from 'vue';
const count = 0;
const rCount = ref(count);
for(let i = 1; i <= 5; ++i){
	rCount.value = i;
}
</script>

代码二:

vue
<template>
	<div>{{rCount}}</div>
</template>
<script setup>
import { ref } from 'vue';
const count = 0;
const rCount = ref(count);
for(let i = 1; i <= 5; ++i){
 setTimeout(()=>{
   rCount.value = i;
 }, 0);
}
</script>
  • 代码一:2次,初始化渲染1次,之后虽然在 for 循环中修改了 5 次响应式数据,但是会被合并,因此之后只会渲染 1次。
  • 代码二:6次,初始化渲染1次,之后每一个 setTimeout 中修改一次响应式数据就会渲染1次。

参考答案:

代码一(同步赋值)

会渲染两次:

  1. 初始化渲染一次:在组件挂载时,Vue 会进行一次初始渲染,将 rCount 的初始值 0 渲染到 DOM 中。

  2. 响应式数据更新和批处理:

  • 在 for 循环中,rCount.value 被依次赋值为 1, 2, 3, 4, 5. 每次赋值时,Vue 的响应式系统会检测到数据的变化。
  • 然而,这些变化发生在同一个同步代码块内,Vue 会将这些变化推入异步更新队列中。因为这些赋值操作是同步执行的,Vue 会在当前事件循环结束时对这些变化进行批处理(batching)
  • Vue 的批处理机制会将这些同步的更改合并为一次更新,因此,无论有多少次对 rCount.value 的赋值,最终只会在异步队列中触发一次渲染更新。
  1. 最终渲染一次:由于 Vue 的批处理机制,这段代码最终只会触发 一次 DOM 更新,渲染出 rCount 的最终值 5.

总计渲染次数:2 次(初始化渲染 1 次 + 批处理渲染 1 次)

代码二(异步赋值)

会渲染六次:

  1. 初始化渲染一次:同样,组件挂载时会进行一次初始渲染,将 rCount 的初始值 0 渲染到 DOM 中。

  2. 异步更新渲染:

  • 在 for 循环中,每次迭代都会创建一个 setTimeout,每个 setTimeout 会在 0 毫秒后异步执行。在每个 setTimeout 的回调中,rCount.value 被依次赋值为 1, 2, 3, 4, 5
  • 由于每次赋值都发生在一个独立的异步回调中,Vue 的响应式系统会在每个异步回调执行后,立即触发相应的更新流程。每次 setTimeout 回调都会使 rCount.value 发生变化,因此每次都需要进行一次渲染更新。
  1. 每个异步回调导致一次渲染:因此,这段代码会触发 5 次 DOM 更新,每次将 rCount 渲染为 1 到 5.

总计渲染次数:6 次(初始化渲染 1 次 + 5 次异步更新渲染)


-EOF-

Released under the MIT License.