第2章 Vue核心架构解析

2.1 双版本设计:运行时 vs 编译器

2.1.1 版本差异对比

// 完整版(包含编译器)构建过程
new Vue({
  template: '
{{ message }}
'
// 需要编译模板 }) // 运行时版(需预编译)构建过程 new Vue({ render(h) { // 直接使用预编译的render函数 return h('div', this.message) } })

关键差异说明表

特性 完整版 运行时版
体积大小 较大 (~30KB) 较小 (~20KB)
模板编译时机 运行时编译 构建时预编译
使用场景 需要动态模板 推荐生产环境使用
包含模块 compiler + runtime runtime only

2.1.2 编译器的作用原理

// 模板编译过程伪代码
function compile(template) {
  // 阶段1:解析
  const ast = parse(template)
  
  // 阶段2:优化
  optimize(ast)
  
  // 阶段3:生成
  const code = generate(ast)
  
  return {
    render: new Function(code.render),
    staticRenderFns: code.staticRenderFns.map(fn => new Function(fn))
  }
}

编译时 vs 运行时

  1. 编译时阶段(构建时):

    • .vue文件转换为JavaScript对象
    • 模板编译为render函数
    • 应用Tree-shaking优化
  2. 运行时阶段

    • 处理响应式数据
    • 执行render函数生成虚拟DOM
    • 执行DOM diff和更新

2.2 源码目录结构解析

2.2.1 核心目录结构

src/
├── core/                # 核心代码
│   ├── components/      # 内置组件(keep-alive)
│   ├── global-api/      # 全局API(Vue.use等)
│   ├── instance/        # 实例方法(_init, $mount)
│   ├── observer/        # 响应式系统
│   ├── util/            # 工具方法
│   └── vdom/            # 虚拟DOM相关
├── platforms/           # 平台相关代码
│   ├── web/             # Web平台特定代码
│   └── weex/            # Weex平台支持
├── server/              # 服务端渲染
├── sfc/                 # 单文件组件解析
└── shared/              # 共享工具函数

2.2.2 关键文件解析

  1. 入口文件(platforms/web/entry-runtime.js)
import Vue from './runtime/index'

// 安装平台特定工具方法
Vue.config.mustUseProp = mustUseProp
Vue.config.isReservedTag = isReservedTag

// 注入全局API
initGlobalAPI(Vue)

// 挂载原型方法
Vue.prototype.$mount = function(el) {
  // 重写mount方法
}
  1. 响应式核心(core/observer/index.js)
export function observe(value) {
  if (!isObject(value)) return
  let ob
  if (hasOwn(value, '__ob__')) {
    ob = value.__ob__
  } else {
    ob = new Observer(value) // 创建观察者
  }
  return ob
}

class Observer {
  constructor(value) {
    this.value = value
    this.dep = new Dep()
    def(value, '__ob__', this)
    if (Array.isArray(value)) {
      // 处理数组响应式
    } else {
      this.walk(value) // 处理对象响应式
    }
  }
}

2.3 模块依赖关系图

2.3.1 核心模块交互流程

new Vue()
初始化事件/生命周期
initState
数据劫持
编译模板
生成Render函数
创建Watcher
执行Render生成VNode
Patch到真实DOM

2.3.2 响应式系统与虚拟DOM的协作

// 依赖更新流程示例
data.message = 'new' → 
触发setter → 
notify Watcher → 
执行updateComponent → 
调用render函数生成新VNode → 
执行patch比较差异 → 
更新实际DOM节点

关键路径说明

  1. 数据变更:通过响应式系统触发
  2. 视图更新:通过虚拟DOM进行高效更新
  3. 批量更新:使用异步队列避免重复计算
// 异步更新队列实现
function queueWatcher(watcher) {
  if (!flushing) {
    queue.push(watcher)
  }
  if (!waiting) {
    nextTick(flushSchedulerQueue) // 下一个tick执行
  }
}

2.4 设计模式解析

2.4.1 发布-订阅模式

在响应式系统的应用

// Dep(发布者)
class Dep {
  constructor() {
    this.subs = new Set()
  }
  depend() {
    if (Dep.target) this.subs.add(Dep.target)
  }
  notify() {
    this.subs.forEach(watcher => watcher.update())
  }
}

// Watcher(订阅者)
class Watcher {
  update() {
    queueWatcher(this) // 进入更新队列
  }
}

2.4.2 策略模式

在模板编译中的应用

// 指令解析策略
const directiveStrategy = {
  'v-if'(el, value) {
    // 处理if逻辑
  },
  'v-for'(el, value) {
    // 处理循环逻辑
  },
  // ...
}

function processDirectives(node) {
  node.attrs.forEach(attr => {
    const handler = directiveStrategy[attr.name]
    handler && handler(node, attr.value)
  })
}

2.5 核心流程图解

2.5.1 完整初始化流程

1. 初始化Vue构造函数
   ↓
2. 合并选项(mergeOptions)
   ↓
3. 初始化生命周期(initLifecycle)
   ↓
4. 初始化事件系统(initEvents)
   ↓
5. 初始化渲染方法(initRender)
   ↓
6. 调用beforeCreate钩子
   ↓
7. 初始化依赖注入(initInjections)
   ↓
8. 初始化状态(initState) → 响应式处理
   ↓
9. 初始化提供器(initProvide)
   ↓
10. 调用created钩子
   ↓
11. 执行挂载($mount)
   ↓
12. 编译模板 → 生成render函数
   ↓
13. 创建渲染Watcher
   ↓
14. 执行首次渲染 → patch到DOM

2.5.2 模块通信示意图

生成
执行
差异对比
触发更新
通知
编译器
Render函数
虚拟DOM
真实DOM
响应式系统
Watcher

本章重点总结:

  1. 架构分层:理解Vue的模块化架构设计
  2. 双版本机制:掌握运行时与完整版的区别
  3. 模块协作:明确各核心模块的职责边界
  4. 设计模式:识别框架中使用的经典模式

建议练习

  1. 在Vue源码中定位本章提到的关键文件
  2. 使用不同构建版本对比项目体积差异
  3. 调试观察初始化流程的执行顺序

你可能感兴趣的:(vue深入理解,前端,javascript,vue.js)