面试官:vue用三年多了?来说说你是如何理解vue的...

1,884 阅读5分钟

先有问题再有答案

  1. 如何理解vue框架
  2. vue架构可以分为哪些部分?
  3. 如何理解响应式数据系统?
  4. 为什么vue不需要开发者手动处理 性能就很好?

作为前端领域的主流框架之一, Vue.js 的核心任务是将声明式的模板转化为真实的 DOM 并渲染到浏览器上。这一过程由三大部分协作完成: 模板编译处理、数据响应系统和渲染流程

模板编译处理将开发者编写的声明式模板转换为高效的渲染函数,这些函数会被传递给渲染流程部分。

渲染流程负责根据这些函数生成虚拟 DOM 树,并最终渲染到浏览器中的真实 DOM 上。

数据响应系统则担当着监测数据变化的重任。一旦数据发生变化,它会通知渲染流程进行必要的更新,确保视图与数据保持同步。

这三个部分环环相扣, 共同构成了 Vue.js 的高性能和灵活性。

一图胜千言

截屏2024-06-07 下午3.10.01.png

具体步骤如下:

  1. 静态模板编译

    • 这一步通常发生在构建阶段,Vue模板被编译为渲染函数:即用来返回虚拟 DOM 树的函数
  2. 响应式系统数据转换

    • Vue 会遍历组件的 data 对象,用 Object.defineProperty(Vue 2.x)或 Proxy(Vue 3)将它们转换成响应式属性。
  3. 响应式系统的依赖收集

    • 每个响应式属性拥有一个 dep 对象,它维护一份 watcher 列表,该列表包括所有依赖于此属性的 watcher。
  4. 响应式数据变更

    • 当响应式数据发生变化时,对应的 dep 对象通知所有绑定的 watcher 进行更新。
    • 变更的每个属性可能对应多个 watcher(包括渲染 watcher 和用户定义的watcher)。
  5. 更新队列

    • Reactivity system 把准备更新的 watcher 添加到一个异步执行队列中。如果一个 watcher 在同一个事件循环中被多次触发,它只会被加入队列一次(去重)。
  6. 微任务(microtask)的异步更新

    • Vue 通常将更新队列的处理推到下一个 JavaScript 事件循环的微任务(microtask)中。
    • 在微任务队列中,Vue 执行完所有同步代码后,清空更新队列,按照优先级顺序同步地执行队列中的 watcher 更新。
  7. 组件重新渲染(DOM 更新)

    • 队列中的渲染 watcher 被触发,导致组件进行重新渲染,生成新的虚拟 DOM。
    • Vue 使用 "diff" 算法,应用keys机制等,比较新旧虚拟 DOM,计算出最小的更新,做patch操作来应用于实际的 DOM 树上。
  8. nextTick

    • 所有 DOM 更新后,Vue 调用在 nextTick 注册的任何回调。
    • 这确保了调用 nextTick可以在DOM 更新完成后执行一些额外的操作。

响应式数据系统:

一句话说明本质:当数据变化后运行对应的函数。

如何知道数据变化了

通过proxy代理拦截属性赋值setter操作. 所以我们操作的并不是普通的js对象,是经过响应式api处理的添加了setter拦截器的响应式对象。

要运行哪些函数

vue需要知道当前变化的属性,都被哪些函数wacth了。这就需要依赖dep对象在初始化时做依赖收集。 每个响应式对象的属性都对应一个dep实例,dep存储了对应的watcher列表。

什么时间运行函数合适

当找到对应的watcher列表Vue并不会立即运行,而是会将这些wacther加入到队列中 等待这次事件变化结束 所有响应式数据都改动完成,在异步执行这些任务队列。

当执行watcher过程中 又收集到新的响应式数据发生变化 同样将对应的watcher列表加入队列,依次执行 直到任务队列为空,本次批处理结束 触发渲染流程。

<script setup>
import { ref, watch, computed } from 'vue'
const msg = ref('Hello World!')

watch(()=>msg.value,()=>{
  console.log('test watch msg', msg)
})

const msgTo = computed(()=>{
  return  'me: ' + msg.value;
})
</script>

<template>
  <h1>{{ msg }}</h1>
  <input v-model="msg" />
   <h1>{{msgTo}}</h1>
</template>

截屏2024-06-07 下午4.34.04.png

为什么vue不需要开发者手动处理 性能就很好?

编译器对模板的静态优化

因为模板支持的语法结构是固定的,编译器可以静态分析模板并在生成的代码中留下标记,使得运行时尽可能地走捷径。

  1. 静态提升
  2. 更新类型标记
  3. 树结构打平

以上三点源自vue官网

响应式自动追踪

通过响应式api可以自动做依赖收集,获取到哪些组件发生了变化 精准渲染对应的组件。对比react不存在过度渲染的问题。

渲染流程的高效diff

通过渲染流程的diff算法后 计算出需要变更的dom节点被进一步缩小。

总结

通过静态优化大大减少了js的运行时时间。通过响应式自动追踪减少diff范围,通过高效diff算法减少真实操作dom数量。这一切都是vue自动帮我们做的 并不需要开发者手动处理。

其他文章