两道代码题
# 两道代码题
面试题1
完成 Component 类代码的书写,要求:
- 修改数据时能够触发 render 方法的执行
- 同步变更时需要合并,仅触发一次 render 方法
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 中分别渲染几次?为什么?
代码一:
<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>
代码二:
<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次。
参考答案:
代码一(同步赋值)
会渲染两次:
初始化渲染一次:在组件挂载时,Vue 会进行一次初始渲染,将 rCount 的初始值 0 渲染到 DOM 中。
响应式数据更新和批处理:
- 在 for 循环中,rCount.value 被依次赋值为 1, 2, 3, 4, 5. 每次赋值时,Vue 的响应式系统会检测到数据的变化。
- 然而,这些变化发生在同一个同步代码块内,Vue 会将这些变化推入异步更新队列中。因为这些赋值操作是同步执行的,Vue 会在当前事件循环结束时对这些变化进行批处理(batching)
- Vue 的批处理机制会将这些同步的更改合并为一次更新,因此,无论有多少次对 rCount.value 的赋值,最终只会在异步队列中触发一次渲染更新。
- 最终渲染一次:由于 Vue 的批处理机制,这段代码最终只会触发 一次 DOM 更新,渲染出 rCount 的最终值 5.
总计渲染次数:2 次(初始化渲染 1 次 + 批处理渲染 1 次)
代码二(异步赋值)
会渲染六次:
初始化渲染一次:同样,组件挂载时会进行一次初始渲染,将 rCount 的初始值 0 渲染到 DOM 中。
异步更新渲染:
- 在 for 循环中,每次迭代都会创建一个 setTimeout,每个 setTimeout 会在 0 毫秒后异步执行。在每个 setTimeout 的回调中,rCount.value 被依次赋值为 1, 2, 3, 4, 5
- 由于每次赋值都发生在一个独立的异步回调中,Vue 的响应式系统会在每个异步回调执行后,立即触发相应的更新流程。每次 setTimeout 回调都会使 rCount.value 发生变化,因此每次都需要进行一次渲染更新。
- 每个异步回调导致一次渲染:因此,这段代码会触发 5 次 DOM 更新,每次将 rCount 渲染为 1 到 5.
总计渲染次数:6 次(初始化渲染 1 次 + 5 次异步更新渲染)
-EOF-