Wang's blog Wang's blog
首页
  • 前端文章

    • HTML教程
    • CSS
    • JavaScript
  • 前端框架

    • Vue
    • React
    • VuePress
    • Electron
  • 后端技术

    • Npm
    • Node
    • TypeScript
  • 编程规范

    • 规范
  • 我的笔记
  • Git
  • GitHub
  • VSCode
  • Mac工具
  • 数据库
  • Google
  • 服务器
  • Python爬虫
  • 前端教程
更多
收藏
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Wang Mings

跟随大神,成为大神!
首页
  • 前端文章

    • HTML教程
    • CSS
    • JavaScript
  • 前端框架

    • Vue
    • React
    • VuePress
    • Electron
  • 后端技术

    • Npm
    • Node
    • TypeScript
  • 编程规范

    • 规范
  • 我的笔记
  • Git
  • GitHub
  • VSCode
  • Mac工具
  • 数据库
  • Google
  • 服务器
  • Python爬虫
  • 前端教程
更多
收藏
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Python爬虫

  • 前端教程

    • 团队规范

    • Project

    • JS

    • NodeJS

    • Vue

      • 个人理解Vue和React区别
      • Vue高级用法
      • Vue2.x源码分析 - 框架结构
      • Vue2.x源码分析 - 模版编译以及挂载
      • 虚拟dom算法库 - snabbdom
      • Vue2.x源码分析 - Virtual DOM实现
      • Vue2.x源码分析 - 事件系统
      • Vue2.x源码分析 - 组件系统
      • Vue2.x源码分析 - Vue.nextTick
      • Vue2.x源码分析 - inject provide
      • Vue2.x源码分析 - 解析Template模板
      • Vue2.x源码分析 - 响应式原理
      • Vue2.x源码分析 - v-model
      • Vue CLI3 插件系统原理
      • Vue Loader v15 源码解析
      • Vue3 设计思想
      • Vue3 RFCS导读
      • Vue3 响应式原理 - Ref Reactive Effect源码分析
      • Vue3 API 源码解析
      • 为何Vue3 Proxy 更快
      • Vue核心原理 - 笔记
        • [#](#_1-new-vue-optionapi-流程) 1. new Vue\(\{ optionAPI \}\)流程
          • [#](#衍生问题) 衍生问题
        • [#](#_2-响应式原理) 2. 响应式原理
          • [#](#_2-1-react状态机模式) 2.1 react状态机模式
          • [#](#_2-2-vue依赖收集模式) 2.2 vue依赖收集模式
          • [#](#vue调度原则) Vue调度原则
    • React

    • 效率工具

    • 读书笔记

  • 教程
  • 前端教程
  • Vue
wangmings
2022-07-19
目录

Vue核心原理 - 笔记

# # Vue核心原理 - 笔记

主要有两块:

  1. new Vue({ optionAPI })流程,即:Vue Option API代码是如何渲染到最终UI
  2. 响应式原理,即:如何依赖收集的,为什么要用Object.defineProperty/Proxy

涉及到的概念:

  1. 模板编译 & runtime
    • VirtualDOM
    • VNode
    • VDiff
  2. 双向数据绑定
    • 依赖收集

本文主要以vue2.x源码为例,vue3中的核心思想原理依然适用

# # 1. new Vue({ optionAPI })流程

问题:下面的js代码如何实现从js代码到Web UI上的渲染?

    new Vue({
        el: el,
        render: h => h(App),
    }) // .$mount('#app');
    
1
2
3
4
5

概念流程:new Vue() => Vitrual DOM => DOM

源码流程:template/jsx -> render() -> Vue.prototype._render() -> vnode -> patch() -> vdiff -> ui(DOM API,web:nodeOps)

涉及到的概念:

  • VirtualDOM、VNode数据结构(VirtualDOM只是概念,VNode才是虚拟DOM的承载)
  • VNode + Diff = patch

# # 衍生问题

  1. 为什么要有VDOM/VNode?答:1. 找到最小更新DOM操作集 2. 给Web之外的终端UI提供可能(比如Native、webgl)
    • 思考:js引擎 / 渲染引擎 (互斥) -> js单线程 (node(libuv),callback,event loop)
    • 浏览器是如何渲染?渲染,js引擎(V8)关系?
    • js -> ui : 假设js多线程? webworker规范: 不能操作dom
    • VNode: tag、children -> leetcode
  2. Vue2:为什么需要包装一个根节点?答:VDiff算法决定了需要这规则

# # 2. 响应式原理

# # 2.1 react状态机模式

react基于状态机:msg -> this.setState({msg}) -> render() -> vdiff -> ui(DOM)

    export default class ReactComp extend React.Component {
        state = {msg : 1}
        render() {
            return <div>{msg}</div>
        }
    
        this.setState({msg: 111}) // -> render()
    
        // 状态机模式:msg -> setState -> render() -> vdiff -> ui(DOM)
        {msg: 1} -> UI1
        {msg: 111} -> UI2
    }
    
1
2
3
4
5
6
7
8
9
10
11
12
13

# # 2.2 vue依赖收集模式

vue基于劫持进行自动依赖收集:msg -> this.msg = 111 \-> Object.defineProperty -> render() -> vdiff -> ui(DOM)

源码流程:this.xxx = 1 -> 中间劫持(defineProperty/Proxy) -> getter/setter -> Dep/Watcher -> Watcher(cb): render/computed/this.$watch() -> render() -> UI

    // vue2.x proxy: Object.defineProperty
    export default {
        render() {
            return <div>{msg}{msgxxx}</div>
        }
        data() {
            return { msg: 11}
        }
        computed: {
            msgxxx() {
                return this.msg + 'hello' // Watcher(() => {return this.msg + 'hello'})
            }
        }
    
        // 双向数据绑定原理:
        Object.defineProperty(data, 'msg', {
            getter() {
                // 依赖收集 Dep: { msg: [Wathcer(() => render()), ] }
                dep(new Watcher(() => render()))
                return value
            }
            setter() {
                // 触发更新
                dep.notify()
            }
        })
    
        this.msg = 111 // js语法,更新值 + 收集的Watcher update
    }
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

自定义依赖者模式:

    // 依赖者
    class Dep {
        arr = []
        dep(watch) {
            arr.push(watch)
        }
        notify() {
            arr.forEach(watch => watch.update())
        }
    }
    
    class Watcher() {
        constructor(cb) {
            this.cb = cb
        }
        update() {
            this.cb()
        }
    }
    
    let dep = new Dep() // msg
    dep(new Watcher(() => render())) // render Watcher
    dep(new Watcher(() => computed())) // computed Watcher
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# # Vue调度原则

  1. 先父组件更新,后子组件更新
  2. render Watcher放在最后执行
    // 如上案例的调度:
    // dep:msg: [WatcherRender(), computedCB(), selfWatcher()]
    // dep:msgxxx: [WatcherRender()]
    
    // 最终根据规则依次执行:[computedCB(), selfWatcher(), WatcherRender]
    
1
2
3
4
5
6
编辑 (opens new window)
为何Vue3 Proxy 更快
Vuex与Redux比较

← 为何Vue3 Proxy 更快 Vuex与Redux比较→

最近更新
01
theme-vdoing-blog博客静态编译问题
09-16
02
搜索引擎
07-19
03
友情链接
07-19
更多文章>
Theme by Vdoing | Copyright © 2019-2022 Evan Xu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式