写点什么

Vuejs 2.0 源码解析之渲染篇

  • 2019-08-21
  • 本文字数:2376 字

    阅读完需:约 8 分钟

Vuejs 2.0源码解析之渲染篇

1、Vuejs 框架是目前比较火的 MVVM 框架之一,简单易上手的学习曲线,友好的官方文档,配套的构建工具,让 Vuejs 在 2016 大放异彩,大有赶超 react 之势。前不久 Vuejs 2.0 正式版已出,优化体积(相比 1.0 减少了 50%),提升性能(相比 1.0 提升 60%),API 优化等,各方面更上一层楼。

2、本文是系列文章,主要想通过对于 Vuejs 2.0 源码的分析,从代码层面解析 Vuejs 的实现原理,帮助读者能够更深入地理解整个框架的思想。此篇文章主要介绍前端渲染部分。

3、不足之处还请批评指正,欢迎一起交流学习。

Vue 的初始化

我们在使用 Vuejs 的时候,最基本的一个使用,就是在 HTML 引入 Vuejs 的库文件,并写如下一段代码:



new Vue,本质就是生成一个 Vue 的对象,我们来了解一下这个生成 Vue 对象的过程是怎样的。


1、首先,vue 的入口是/src/entries/web-runtime-with-compiler.js,这是由 config.js 配置文件决定的。



这个入口文件中 import 了很多文件,其中有一条主要的脉络:



其中/src/core/instance/index.js 是最核心的初始化代码,其中:



红框部分,就是整个 Vue 的类的核心方法。其含义给读者解读一下:



其中 new Vue 就是执行下面的这个函数:



_init 方法就是 initMixin 中的_init 方法



至此,程序沿着这个_init 方法继续走下去。

Vue 的渲染逻辑—render 函数

在定义完成 Vue 对象的初始化工作之后,本文主要是讲渲染部分,那么我们接上面的逻辑,看 Vuejs 是如何渲染页面的。在上图中我们看到有一个 initRender 的方法:



在该方法中会执行红框部分的内容:



而 $mount 方法就是整个渲染过程的起始点。具体定义是在/src/entries/web-runtime-with-compiler.js 中,根据代码整理成流程图:



由此图可以看到,在渲染过程中,提供了三种渲染模式,自定义 render 函数、template、el 均可以渲染页面,也就是对应我们使用 vue 时,三种写法:


1、自定义 render 函数



2、template 写法



3、el 写法(这个就是入门时最基本的写法)



这三种渲染模式最终都是要得到 render 函数。只不过用户自定义的 render 函数省去了程序分析的过程,等同于处理过的 render 函数,而普通的 template 或者 el 只是字符串,需要解析成 AST,再将 AST 转化为 render 函数。


记住一点,无论哪种方法,都要得到 render 函数。


我们在使用过程中具体要使用哪种调用方式,要根据具体的需求来。


1、如果是比较简单的逻辑,使用 template 和 el 比较好,因为这两种都属于声明式渲染,对用户理解比较容易,但灵活性比较差,因为最终生成的 render 函数是由程序通过 AST 解析优化得到的。


2、而使用自定义 render 函数相当于人已经将逻辑翻译给程序,能够胜任复杂的逻辑,灵活性高,但对于用户的理解相对差点。

Vue 的渲染逻辑—VNode 对象 &patch 方法

根据上面的结论,我们无论怎么渲染,最终会得到 render 函数,而 render 函数的作用是什么呢?我们看到在/src/core/instance/lifecycle.js 中有这么一段代码:



意思就是,通过 Watcher 的绑定,每当数据发生变化时,执行_update 的方法,此时会先执行 vm._render(),在这个 vm._render()中,我们的 render 函数会执行,而得到 VNode 对象。



VNode 对象是个什么东西?VNode 就是 Vuejs 2.0 中的 Virtual DOM,在 Vuejs 2.0 中,相较 Vuejs 1.0 引入了 Virtual DOM 的概念,这也是 Vuejs 2.0 性能提升的一大关键。Virtual DOM 有多种实现方式,但基本思路都是一样的,分为两步:

1、Javascript 模拟 DOM 模型树

在 Vuejs 2.0 中 Javascript 模拟 DOM 模型树就是 VNode,render 函数执行后都会返回 VNode 对象,为下一步操作做准备。在/src/core/vdom/vnode.js 中,我们可以看到 VNode 的具体数据结构:



VNode 的数据结构中还有 VNodeData, VNodeDirective, VNodeComponentOptions,这些数据结构都是对 DOM 节点的一些描述,本文不一一介绍。读者可以根据源码来理解这些数据结构。(PS:Vuejs 使用了 flow,标识了参数的静态类型,对理解代码很有帮助^_^)

2、DOM 模型树通过 DOM Diff 算法查找差异,将差异转为真正 DOM 节点

我们知道 render 函数执行生成了 VNode,而 VNode 只是 Virtual DOM,我们还需要通过 DOM Diff 之后,来生成真正的 DOM 节点。在 Vuejs 2.0 中,是通过/src/core/vdom/patch.js 中的 patch(oldVnode, vnode ,hydrating)方法来完成的。


该方法有三个参数 oldVnode 表示旧 VNode,vnode 表示新 VNode,hydrating 表示是否直接使用服务端渲染的 DOM 元素,这个本文不作讨论,在服务端渲染篇再详细介绍。


其主要逻辑为当 VNode 为真实元素或旧的 VNode 和新的 VNode 完全相同时,直接调用 createElm 方法生成真实的 DOM 树,当 VNode 新旧存在差异时,则调用 patchVnode 方法,通过比较新旧 VNode 节点,根据不同的状态对 DOM 做合理的添加、删除、修改 DOM(这里的 Diff 算法有兴趣的读者可以自行阅读 patchVnode 方法,鉴于篇幅不再赘述),再调用 createElm 生成真实的 DOM 树。

Vue 的渲染小结

回过头来看,这里的渲染逻辑并不是特别复杂,核心关键的几步流程还是非常清晰的:


1、new Vue,执行初始化


2、挂载 $mount 方法,通过自定义 render 方法、template、el 等生成 render 函数


3、通过 watcher 监听数据的变化,当数据发生变化时


4、render 函数执行生成 VNode 对象


5、通过 patch 方法,对比新旧 VNode 对象,通过 DOM Diff 算法,添加、修改、删除真正的 DOM 元素


至此,整个 new Vue 的渲染过程完毕。


作者介绍:


王鹤,腾讯前端高级工程师,参与过 QQ 情侣、QQ 星影联盟、QQ 个性化装扮等项目的研发。秉承「不想当产品经理的程序员,不是好的设计师」。除敲敲代码外,对产品、设计、摄影也有一定的兴趣。欢迎一起交流,谈理(CHUI)想(SHUI),聊人(BA)生(GUA)~


本文转载自公众号小时光茶舍(ID:gh_7322a0f167b5)。


原文链接:


https://mp.weixin.qq.com/s/-ykt8u1N50vRnFp2A_4m8Q


2019-08-21 10:381591

评论

发布
暂无评论
发现更多内容

几个常见的js手写题,你能写出来几道

helloworld1024fd

JavaScript

公交车LED电子路牌宣传效果更好吗

Dylan

LED显示屏 户外LED显示屏 led显示屏厂家

中移链合约常用开发介绍 (一)开发基本流程

BSN研习社

中移链

TiDB Operator数据导入

TiDB 社区干货传送门

迁移 集群管理 管理与运维 备份 & 恢复

深度剖析 | 【JVM深层系列】[HotSpotVM研究系列] JVM调优的"标准参数"的各种陷阱和坑点分析(攻克盲点及混淆点)「 1 」

码界西柚

JVM 12 月 PK 榜 调优参数 调优技术

民航二所马勇:数据安全防护体系的探索与思考

极盾科技

数据安全

重写Nacos服务发现:多个服务器如何跨命名空间,访问公共服务?

LigaAI

Java 测试 nacos 测试环境 12 月 PK 榜

搜电充电:创新“服务卡片”,让即时充电更便捷

HarmonyOS开发者

HarmonyOS

前端二面高频手写面试题

helloworld1024fd

JavaScript

TiDB增强型 StatefulSet 控制器--Advanced StatefulSet

TiDB 社区干货传送门

集群管理 管理与运维 安装 & 部署 扩/缩容

从TiDB搭建到监控闭环

TiDB 社区干货传送门

监控 管理与运维

百TB级TiDB集群在线更换NVME磁盘优化实践

TiDB 社区干货传送门

性能调优 管理与运维 应用适配 6.x 实践 大数据场景实践

【12.9-12.16】写作社区优秀技术博文一览

InfoQ写作社区官方

热门活动

GaiaX开源解读 | 给Stretch(Rust编写的Flexbox布局引擎)新增特性,我掉了好多头发

阿里巴巴文娱技术

开源 rust 后端 rust语言 GaiaX

XTransfer技术专家亮相Flink Forward Asia 2022

XTransfer技术

别再秃头背锅了!这个小技巧统计第三方接口耗时很安逸

Java永远的神

Java 程序员 后端 架构师 springboot

社招前端常考手写面试题总结

helloworld1024fd

JavaScript

RocketMQ Connect 构建流式数据处理平台

Apache RocketMQ

RocketMQ Connect

全球首家!星环科技通过3TB TPCx-AI测试,实现大数据与AI的完美融合

星环科技

TiCDC 在多种场景的新特性的应用

TiDB 社区干货传送门

安装 & 部署 OLTP 场景实践

星环数据云平台 TDC 3.1 发布,新增滚动重启、存储回收站等八大核心功能

星环科技

聊聊电商系统架构, 常见的9个大坑

Java全栈架构师

程序员 后端 架构师 电商 系统秒杀

TiDB Operator扩缩容和集群的管理

TiDB 社区干货传送门

集群管理 管理与运维 安装 & 部署 扩/缩容

Lightning checksum failed 报错实践案例

TiDB 社区干货传送门

破记录!国产数据库KunDB 单节点TPC-C事务性能超180万tpmC

星环科技

将渲染计算搬到云端,开启低成本、强交互、沉浸式体验

阿里云CloudImagine

云计算 阿里云 云渲染 串流

五大亮点来袭!神州云科冬季发布会报名通道开启,千份精美礼品等你来拿!

通明湖

【敏捷转型,效能提升】敏捷转型实践系列分享

京东科技开发者

敏捷 敏捷团队 效能度量 效能提升 #DevOps

性能最大提升60%,阿里云发布基于第四代英特尔至强的第八代ECS实例

云布道师

阿里云

手把手教你成为荣耀开发者:应用管理指南

荣耀开发者服务平台

前端 快应用 荣耀 honor 应用集成

Vuejs 2.0源码解析之渲染篇_语言 & 开发_王鹤_InfoQ精选文章