Vue3源码梳理:关于运行时和编译时

Vue3源码分析——编译模块和编译器 Vue3的编译模块包含4个目录: compiler-core // 编译核心 Compiler-DOM // 浏览器相关 Compiler-sfc // 单文件组件 Compiler-SSR // 服务端渲染 其中,compiler-core模块是Vue编译的核心模块,与平台无关。其余三个基于compiler-core,适用于不同的平台。 Vue的编译分为三个阶段,即解析(Parse)、转换(Transform)和代码生成(Codegen)。 Parse阶段将模板字符串转换为语法抽象树... 阅读详情

运行时和编译时的概念

  • vue中的html是真实的html么?

  • .vue文件是单文件组件, 在template中写入的html是真实的html标记节点么?

    <template>
      <div v-if='false'>hello</div>
      <m-com />
    </template>
    
  • 上述 v-if 和 m-com 自定义组件不是正常的html, 浏览器是不认识的,所以不会解析

  • 上面两个两个问题的答案都是否定的

  • 但是我们的浏览器正确渲染了结果,这里vue一定在中间做了处理

  • 这个过程主要是:让假标记,被渲染成真实的html标签,最终呈现给用户

  • 从这方面来说,Vue的核心功能,分为三项:

    • 运行时:runtime
    • 编译时:compiler
    • 运行时 + 编译时: runtime + compiler
  • vue的响应式系统是一个 运行时 + 编译时 结合的复合系统

  • 这三个概念早就提出过,vue也是使用了这个方案

运行时

  • vuejs/core/tree/main/packages
    • runtime-core
      • 这里对外暴露出一个函数:render
      • 用于编程式地创建虚拟DOM树的函数
      • 作用是:代替template模板来完成 DOM 的渲染
    • runtime-dom
  • 使用render函数渲染出一个div
    <script src='vue.js'></script>
    <div id="app"></div>
    <script>
      const { render, h } = Vue
      // 生成vnode
      const vnode = h('div', {class: 'test'}, 'hello render')
      // 找到div容器
      const box = document.querySelector('#app')
      // 渲染
      render(vnode, box)
    </script>
    

render函数内部如何实现

假如基于的一个json想要渲染出一个页面, 应该如何实现

json如下

{
  type: 'div',
  props: {
    class: test
  },
  children: 'hello render'
}

渲染出结果如下的div

<div class='test'>hello render</div>

原生js实现

const vnode = {
  type: 'div',
  props: {
    class: 'test'
  },
  children: 'hello render'
}

function render(vnode) {
  const ele = document.createElement(vnode.type)
  ele.className = vnode.props.class
  ele.innerText = vnode.children
  document.body.appendChild(ele)
}

render(vnode)
  • 以上的代码结构,就是一个运行时的代码框架
  • 当然不考虑树的递归处理,仅仅处理这一个程序示例
  • 简单总结:运行时,利用render把 vnode 渲染成真实 dom 节点
  • 如果想通过 template 模板编写 html 的方式,就不是运行时的方式了

编译时

  • 运行时做不到的事情,通过html标签结构的方式来渲染解析成真实的dom节点

  • vue中的编译时,准确来说是编译器的意思,核心代码在 compiler-core模块下

    const { compile, createApp } = Vue
    const html = `
      <div class='test'>hello compiler</div>
    ` 
    const app = createApp({
      render: compile(html)
    })
    app.mount('#app')
    
  • 也就是把html字符串借助compile的方式变成render函数,再通过render函数渲染出真实dom

  • 编译器的主要作用

    • 把template的html编译成render函数,再利用 运行时
    • 基于render 挂载对应的 dom
  • 简单总结:编译时,把html的模板,编译成render函数

Vue为什么要设计成运行时和编译时这样

  • 如果 compile 函数已经可以把 模板解析了,为何还要生成一个 render 函数
  • 然后,再通过 render 函数进行挂载,这不多此一举?
  • vue为何这样做?

1 )需要先知道dom渲染是如何进行的

可分为两部分

  • 初次渲染,可以叫做挂载
  • 更新渲染,叫做打补丁

初次渲染

容器盒子

<div id='app'></div>

需要渲染的节点

<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
</ul>

初次渲染,会生成一个ul标签,同时生成三个li标签,并把他们挂载到div中

更新渲染

此时ul里的内容发生了变化

<ul>
  <li>3</li>
  <li>1</li>
  <li>2</li>
</ul>

li标签发生了顺序变化,期望浏览器如何更新渲染,有两种方案:

  • a. 清空ul内容,重新渲染li节点
    • 这种简单直接,但是操作执行dom次数多
  • b. 删除原位置的 li-3,在新位置插入li-3
    • 对比旧节点和新节点之间差异,根据差异,把原先最下面的删除,再新增一个新节点
    • 这样,dom操作显著减少,js上的逻辑增多
  • 但是哪种效率更高呢

2 )下面是对比测试

2.1 )1万个dom节点的生成

<body></body>
<script>
  const len = 10000
  console.time('element')
  for (let i = 0; i < len; i++) {
    const div = document.createElement('div')
    document.body.appendChild(div)
  }
  console.timeEnd('element')
</script>

2.2 )1万个js对象的生成

<body></body>
<script>
  const len = 10000
  const divList = []
  console.time('js')
  for (let i = 0; i < len; i++) {
    const json = { type: 'div' }
    divList.push(json)
  }
  console.timeEnd('js')
</script>
  • 耗时数据差距非常明显,我们可以看到js的计算性能远超过dom操作
  • 这里, 即便是dom操作也有优化的空间, 比如通过DocumentFragment批量操作dom, 但是相对比之下 js 操作性能永远大于 dom 操作的性能

vue被设计成运行时和编译时框架

  • 对于纯运行时,不存在编译器,每次渲染,我们需要提供一个复杂的js对象
  • 对于纯编译时,因为缺少运行时计算,所以它只能把分析差异的操作,放到编译时进行,同样,因为省略了运行时,速度可能会更快,但是这种方式将会损失灵活性
    • 可以查看官方文档,渲染函数 & JSX 和 渲染机制
    • 再比如,svelte, 是一个纯编译时框架,但是它实际运行速度达不到理论上的速度
  • 运行时 + 编译时:vue和react都是通过这种方式构建的,使其保持灵活性的基础上,尽量的进行性能的优化,达到一种平衡

副作用

  • 当对数据进行 setter 或 getter 操作时,所产生一系列的后果
  • 副作用可能会有多个

1 ) setter

  • 赋值操作,比如执行下面代码
    msg = 'hello world'
    
  • 这时 msg 就触发了一次 setter 的行为
  • 假如说, msg 是一个响应性数据,这样一次数据改变,就会影响到对应的 视图改变
  • 我们就可以说, msg 的 setter 行为,触发了一次副作用,导致视图跟随发生了变化

2 ) getter

  • getter 所表示的是取值的操作,比如,我们执行如下代码时
    element.innerText = msg
    
  • 对于变量 msg 而言,触发了一次 getter 操作,这一次取值操作,同样会导致 element 的 innerText发生改变
  • 所以,我们可以说:msg 的 getter 行为触发了一次副作用,导致 element 的 innerText 发生了变化
  • Vue的响应性的核心,就依赖这两个特性: getter和setter

3 ) 副作用会产生多个么

可以的

<template>
  <div>
    <p>{{ obj.name }}</p>
    <p>{{ obj.age }}</p>
  </div>
</template>
<script>
  const obj = ref({
    name: '张三',
    age: 30
  })
  obj.value = {
    name: '李四',
    age: 18
  }
</script>

一次setter操作,会导致两个p标签内容变化,这就是多个副作用的体现

vue3设计核心

  • vue3的核心可分为三大模块
    • 响应性:reactivity
    • 运行时:runtime
    • 编译器:compiler

基于以下代码示例来说明

<template>
  <div> {{ proxyTarget.name }} </div>
</template>

<script>
  import { reactive } from 'vue'
  export default {
    setup() {
      const target = {
        name: '张三'
      }
      const proxyTarget = reactive(target)
      return {
        proxyTarget
      }
    }
  }
</script>
  • 首先对于 响应性 reactivity 而言,对外暴露出 reactive 方法
    • 它可以接收一个复杂数据类型参数(被代理对象),返回一个 proxy 对象,也就是代理对象
    • 当 这个代理对象 proxyTarget 触发 getter 和 setter 行为时,都会产生对应的副作用
  • 对于 编译器 compiler 而言,将模板转化为 render 函数
    • 会把 template 里的div进行解析,解析出的内容变为 render 函数
  • 最后,运行时 runtime 会把compiler返回的 render 函数进行渲染,从而得出真实dom
vue核心原理之--理解框架的编译时与运行时 现在我们已经大概了解了什么是运行时编译时编译+运行时、纯编译时等框架的区别,其实在我们使用的现代框架中Vue就是一个编译+运行时的框架。由于它没有编译的过程,因此我们没办法分析用户提供的内容,但是如果加入编译步骤,可能就大不一样了,我们可以分析用户提供的内容,看看哪些内容未来可能会改变,哪些内容永远不会改变,这样我们就可以在编译的时候提取这些信息,然后将其传递给Render函数,Render函数得到这些信息之后,就可以做进一步的优化了。然而,假如我们设计的框架是纯编译时的,那么它也可以分析用户提供的内容。 阅读详情

相关推荐

Vue3面试通关秘籍:从Composition API到性能优化实战解析

本文深入解析Vue3面试核心要点,涵盖Composition API实战、性能优化策略及高级特性应用。从响应式原理到源码级面试题解析,提供全面的Vue3技术指南,帮助开发者掌握面试必备知识点,提升前端开发能力。

weixin_29005499的博客 177

读懂vue源码必懂什么叫运行时和编译时

了解运行时和编译时的相关知识,了解纯运行时、纯编译时以及两者都支持的框架各有什么特点,并总结出Vue.js 3 是一个编译时 + 运行时的框架,它在保持灵活性的基础上,还能够通过编译手段分析用户提供的内容,从而进一步提升更新性能。

陈开心的博客 2242

Vue中的运行时和编译时详细区别

本文就介绍了Vue的模板编译过程的基础内容,下面案例可供参考​​编译阶段​​:模板 → 渲染函数(虚拟 DOM 生成逻辑)优化静态内容(如静态节点提升)运行阶段​​​​执行渲染函数生成虚拟 DOM。数据变化时触发 Diff 比对和 DOM 更新

唐璜Taro的博客 396

【Vue原理系列】(一)简要总结Vue3运行时+编译时原理

要讨论vue3的运行时和编译时框架设计,我们可以先来看看 什么叫命令式什么叫声明式? 首先我们先确定 Vue3是运行时+编译时的框架,其次我们再来看看为什么是?单纯的运行时或者编译时又有什么优缺点呢?命令式框架最突出的就是关注编码过程,例如Jquery就是一个命令式框架哟。 所以,命令式就是看中过程,有种隐隐的过程与代码的逻辑一一对应的感觉。声明式更关注结果,内部过程则是予以封装了。 例如上面的代码可以用声明式的方式: 看起来很简洁吧,这是Vue封装后的。但Vue的内部实现一定是命令式的,只是暴露给开发者的

Younguys 2415

Vue3 响应式系统源码解析:Proxy 依赖收集与编译时优化

响应式系统是现代前端框架的核心机制,通过拦截数据访问与修改实现视图自动更新。其原理基于依赖收集与触发调度,利用 Proxy 替代 Object.defineProperty 解决新增属性监听与数组索引拦截等痛点,配合 WeakMap 存储依赖关系避免内存泄漏。技术价值在于提升运行时性能与开发体验,应用场景包括单页应用、复杂组件状态管理及模板编译优化。Vue3 源码中,Proxy 拦截、track 与 trigger 机制、微任务调度及 PatchFlag 静态提升共同构成了高效响应式体系,理解这些设计有助于

weixin_33226816的博客 270

运算放大器测试方法-输入失调电压

由于运放输入回路的不对称性,在输入端将产生一定的误差信号,从而限制运放信号灵敏度。通常用输入失调电压(VOS)、输入失调电流(Ios)和输入偏置电流(IB)表示。运放有四个主要特征:输入失调特征、开环特征、共模特征及输出特征。其放大倍数较大,由于外界的影响,即使运放的输入端产生较小的输入信号,经过放大,在输出端也会产生较大的误差。为能精确测量其性能,一般采用辅助运放进行测试。下面着重讲了运放的主要参数及如何精确测量这些参数。文中DUT代表被测运放,A代表辅助运放。

weixin_46135931的博客 1万+

Vue2源码梳理:源码构建流程与运行时和编译时的版本选择

在 Vue.js 2.0 中,最终渲染都是通过 render 函数,如果写 template 属性,则需要编译成 render 函数。所以我们写的 .vue 文件在运行的时候已经编译成 js 函数了,并且模板部分已经编译成 render 函数了。很显然,这个编译过程对性能会有一定损耗,所以通常开发阶段更推荐使用 Runtime-Only 的 Vue.js。而 .vue文件 是在编译过程中,通过 vue-loader 处理的。那么这个编译过程会发生运行时,需要带有编译器的版本。打开 .config 文件。

Wang的专栏 1617

Ferry工单平台部署

ferry工单平台部署

运维求生之路 1897

Vue3源码学习9——运行时+编译时

基于之前的以及,其实Vue3的都梳理完成了,最后要做的一步就是它们,以实现真实Vue3使用时的样子实际使用Vue3的时候,大概是这么用的这里的过程涉及两部分apptemplaterendertemplateapp。

gaotlantis的博客 689

Rocky Linux 9.2:利用LVM动态调整/home与/根分区空间分配

本文详细介绍了在Rocky Linux 9.2系统中,如何利用LVM(逻辑卷管理器)动态调整/home与根分区(/)的空间分配。针对根分区空间不足而/home分区闲置的常见问题,文章提供了从检查磁盘布局、备份数据、卸载分区、调整逻辑卷大小到重建文件系统的完整操作步骤,并重点说明了XFS与EXT4文件系统在缩容时的不同处理方法,帮助系统管理员安全、在线地实现存储空间的灵活调配。

weixin_29271263的博客 179

树莓派4B玩转ROS2 Humble:Ubuntu Desktop一键安装与配置教程

本文详细介绍了在树莓派4B上安装和配置ROS2 Humble的完整教程,包括硬件准备、Ubuntu Desktop系统安装、一键部署ROS2、网络配置优化以及常见问题解决方案。通过简化安装流程和性能调优技巧,帮助开发者快速搭建机器人开发环境,充分发挥树莓派4B在ROS2应用中的潜力。

w8x9y0z1的博客 969

Vue 3 性能优化实战:从编译时标记到静态提升与运行时优化

在前端应用日益复杂的今天,虚拟 DOM diff 的性能成为影响页面流畅度的关键因素。Vue 3 通过编译阶段的 patchFlag 标记与静态提升(hoistStatic),将模板中动态与静态节点分离,使得运行时只需对比动态节点,大幅减少不必要的计算和重复创建。结合 Block Tree 与快速 diff 算法,在长列表、报表页、文章详情等静态占比高的场景中,渲染更新效率得到显著提升。理解编译器与运行时如何分工协作,掌握模板结构设计对优化效果的影响,才能让 Vue 3 的性能优势真正落地。

weixin_29628635的博客 124

HFSS实战:手把手教你设计一款小型化圆极化微带天线(附仿真文件)

本文详细介绍了使用HFSS设计小型化圆极化微带天线的完整流程,包括工程初始化、辐射贴片设计、仿真设置与优化等关键步骤。通过实战案例,帮助工程师掌握圆极化天线设计技巧,解决轴比控制和耦合馈电匹配等核心问题,适用于物联网终端和便携式设备应用。

weixin_32770423的博客 340

从Vue3源码深入理解ref响应式

首先我们要去学习源码,就要对整个项目有一个基本了解,了解每个模块、每个目录的作用,这样对我们后期阅读源码也会有很大的帮助;我们将项目从Github上克隆下来:bash代码解读复制代码如果因为网络问题克隆不下来,点击这个链接获取源码;笔者克隆下来时,当前版本号为3.5.12。我们看到整个项目的目录还是非常多的,又有编译时,又有运行时的目录,主要的代码都存放在packages目录,因此我们主要看下它下面的目录结构:bash代码解读复制代码。

qq_66118130的博客 1020

Monorepo与pnpm:前端项目管理的完美搭档

pnpm又称 performant npm,翻译过来就是高性能的npm。Monorepo是一种项目开发与管理的策略模式,它代表"单一代码仓库"(Monolithic Repository)。在Monorepo模式中,所有相关的项目和组件都被存储在一个统一的代码仓库中,而不是分散在多个独立的代码仓库中,这些项目之间还可能会有依赖关系。

m0_68271787的博客 2562

【数据集】3D-GloBFP:全球首个三维建筑轮廓数据集

【数据集】3D-GloBFP:全球首个三维建筑轮廓数据集

WW、forever的博客 1691

Vue 3 的运行机制

Vue 3 运行机制分三级拆解:应用级(createApp 创建上下文)、组件级(从编译到挂载的完整生命周期)、响应式级(Proxy 数据驱动更新)。核心流程包括:编译模板生成带优化标记的 VNode→响应式数据追踪依赖→调度器批量触发更新→基于 PatchFlag 的靶向 DOM 更新。通过静态提升、异步批处理等优化策略,实现高效渲染。整个过程由生命周期钩子串联,形成从数据变更到视图更新的完整闭环。

循环编织时间年轮,递归叩问存在本质,谁能在硅基荒原上,种出思想的玫瑰…… 946

TIA protal与SCL从入门到精通(4)——软件单元使用

平台: TIA portal 15.1 1.添加软件单元 添加软件单元如下图: 关于软件单元使用基本限制,看如下文章即可 TIA protal与SCL从入门到精通(3)——软件单元基本介绍 每个软件单元是一个独立结构,所以每个软件单元的运行方式与实际PLC类似,所以首先添加主函数块: 注意:无论系统是否是具有并发性(这里不要混淆并行与并发的概念),在PLC所有主函数执行总是按主函数依次完成...

苦走一口田 7380

Vue 3 核心原理与实战:从响应式到企业级应用

Vue 3 核心原理与实战指南 本文全面解析 Vue 3 的核心技术升级与最佳实践。重点探讨了: 响应式系统革命:采用 Proxy 替代 defineProperty,实现更高效的属性监听和惰性劫持 编译时优化:通过 Patch Flag 和静态提升技术大幅提升虚拟 DOM 性能 开发范式演进:Composition API 提供更好的逻辑复用与 TypeScript 支持 现代化工具链:推荐使用 Vite 构建工具、Pinia 状态管理和 Nuxt 3 全栈框架 文章通过代码示例和原理对比,帮助开发者从

1221

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Vue3性能优化实战:从编译到运行的全方位提升

前端性能优化是现代Web开发的核心课题,尤其在Vue3框架中,通过编译时优化和运行时调优可以显著提升应用性能。编译阶段利用静态节点提升和Tree Shaking能有效减少打包体积,而运行时的响应式系统优化则通过shallowRef等API避免不必要的性能开销。这些技术手段在大型后台管理系统和电商平台等场景中尤为重要,能直接提升用户体验。本文以Vue3为例,详细解析如何通过组件拆分、虚拟滚动等具体方案实现性能飞跃,其中静态提升和shallowRef等热词技术在实际项目中可带来40%以上的性能提升。

weixin_33417488的博客 206

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

我的Vue2/Vue3知识框架汇总

基础一定要多看,很多看似复杂的bug,实际都是基础问题,不要把时间浪费在修复基础问题的bug上。本文以知识点总结为主,将技术点连成线,再结成网,不管面试官问啥,都能扯一扯啦~最近总感觉知道的越多之后,不知道的更多;还有许多需要学习的,总结这篇文章之后,也该需要制定个以后的学习计划了。然后这篇关于vue2/vue3的文章也算是一个阶段性的总结吧,有了对vue框架的理解,相信再上手框架的学习也会有帮助。

铁锤妹妹的博客 1956

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

vux 源码分发:为什么选择 .vue 源码而不是打包后的 js 文件

本篇指南解析 vux 移动端 UI 组件库的一项核心设计决策:为什么以 `.vue` 源码形式(而非预打包的 js 文件)向开发者分发组件。文章将梳理预打包方案在移动端场景下的四大痛点,说明源码分发如何解决这些问题,并深入 vux-loader 的编译时处理机制,结合仓库源码展示 `merge` 方法、前置 loader 及各编译时插件的实际工作方式。读完你将理解"源码分发 + 编译时处理"这一分

gitblog_00697的博客 530

vue 全局静态变量_Vue源码探秘(一)

引言 Vue作为当前前端开发中比较重要的框架,在企业级开发中应用十分广泛。目前也是我的主要技术栈之一。在接下来的系列文章中,我将带大家一起探秘Vue.js底层源码。本篇文章是Vue源码探秘的第一篇。在这一篇中,我主要是带大家做一些准备工作,介绍一下flow、源码目录和源码构建流程。认识flow flow是facebook 出品的 JavaScript 静态类型检查工具。Vue.js 的源...

weixin_42523846的博客 372

vue3原理思维导图

DSL:一种领域下,特定语言的编译器本质:一段程序,可以把A语言翻译成 B 语言,把 template 模板,编译成 render 渲染函数编译流程完整的编译流程源代码 ➡ 词法分析 ➡ 语法分析 ➡ 语义分析 ➡ 中间代码生成 ➡ 优化 ➡ 目标代码生成 ➡ 目标代码编译前端:词法分析 ➡ 语法分析 ➡ 语术分析编译后端:间代码生成 ➡ 优化 ➡ 目标代码生成Vue的编译流程模板 ➡ 词法分析 ➡ 语法分析。

希望粉丝数量比文章多!!! 278

Vue2到Vue3全家桶升级实战指南

本文提供了从Vue2升级到Vue3全家桶的完整实战指南。文章详细阐述了升级的必要性,包括性能提升、打包体积优化及Composition API带来的开发体验革新。核心内容涵盖升级前的项目评估与规划、核心API变更(如生命周期、v-model、过滤器)的适配方法、Composition API的实战应用,以及Vue Router 4、Pinia状态管理和Vite构建工具等生态库的升级策略,并总结了迁移过程中的常见问题与避坑指南。

xk7n92h3p5m的博客 539

Vue2与Vue3 Diff算法深度对比:从双端Diff到最长递增子序列

虚拟DOM是前端框架高效渲染的基础,diff算法则是衡量性能的关键一环。Vue2采用双端diff,通过四个指针尽可能复用节点;Vue3引入快速diff,借助最长递增子序列将DOM移动次数降至最优。同时,Vue3编译阶段的patchFlag和Block Tree机制,让diff只关注动态节点,进一步减少无意义的比较开销。在长列表拖拽排序、复杂模板频繁更新等场景中,Vue3性能优势更为明显。理解两代diff的设计取舍,有助于开发者合理使用key、规避常见性能陷阱,实现更优的前端工程实践。

weixin_30166691的博客 215
上一篇: 设计模式: 关于编程范式的声明式和命令式编程及应用框架的开发和设计原则
下一篇: Vue3源码梳理:源码目录结构及源码阅读方法
Wang's Blog
博客等级 码龄12年 7434粉丝 2421原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值