源码阅读:究竟怎样才算是读懂了?

市面上有很多源码分析的文章,就我看到的而言,基本的套路就是梳理流程,讲一讲每个模块的功能,整篇文章有一大半都是直接挂源码。我不禁怀疑,作者真的看懂了吗?为什么我看完后还是什么都不懂呢?

事实上一个经过无数次版本迭代的框架源码并不适合初学者直接阅读,因为里面有太多细节,太多噪点,太多枝枝蔓蔓。要想真正理解框架的核心逻辑,必须剥茧抽丝,还原出一个纯净的雏形。如同 jQuery 最早的版本只有六百多行,我相信 Vue 的核心功能也只需要几百行就能实现。所以,读懂源码的标志就是还原,码越薄,真相就越清晰。

如何还原雏形?

一开始我设想的还原过程就是先删后拆。什么报错信息、参数校验、非核心功能全部砍掉,八千行变成了五千行。然后再拆,按功能模块将一个 Vue.js 拆分成 util.js, observer.js, watcher.js …

理想状态下,我应该能够理解源码了吧,可做完解剖手术后,我发现里面的逻辑依然纷繁复杂,剪不断,理还乱,草蛇灰线,伏脉千里,即便换了一个更早期更简短的版本,仍然很快又陷入了永无止境的细节中。

最终我得出结论:与其根据源码还原雏形,不如参考源码自己从头实现一个雏形。

定义核心

Version:2.0.4

只考虑 runtime 版本,不考虑模板编译,不考虑服务端渲染。

核心功能:响应式的数据绑定、虚拟 DOM、diff 算法、patch 方法(用于更新真实 DOM)

如果你对上述基础概念完全不熟,建议先积累一些背景知识:关于响应式绑定参考这篇文章,关于 virtual dom 和 diff 算法参考这个视频。当然,这些并不是必须的。

目标

事实上,Vue-cli 生成的项目中,<template> 标签中的内容都会被编译为 render 函数,render 函数返回整棵虚拟节点树。我们最终要实现一个 Vue,来完成上面的示例。

当 new Vue() 的时候发生了什么?

我们的实现会参考源码的套路,但会大量的简化其中的细节。为了理解源码的结构,最好的突破口就是了解程序的起点 new Vue() 的背后究竟发生了什么。

简单梳理下源码的执行流:

=> 初始化生命周期

=> 初始化事件系统

=> 初始化state,依次处理 props、data、computed …

=> 开始渲染 _mount() => _render() 返回 vdom=> _update() => __patch__() 更新真实DOM

更详细的说明可以参考这篇文章,我们只会实现其中最核心的部分

第一步:将虚拟 DOM 树渲染到真实的 DOM

每一个 DOM 节点都是一个 node 对象,这个对象含有大量的属性与方法,虚拟 DOM 其实就是超轻量版的 node 对象。

我们要生成的 DOM 树看上去是这样的:

关于 data 参数的属性,请参考官方文档

随后我们会通过 createElm 方法和 createChildren 方法的相互调用,遍历整棵虚拟节点树,生成真实的 DOM 节点树,最后替换到挂载点。

完整代码

第二步:修改数据,执行 diff 算法,并将变化的部分 patch 到真实 DOM

diff 算法的逻辑比较复杂,可以单独摘出来研究,由于我们的目的是理解框架的核心逻辑,因此代码实现里只考虑了最简单的情形。

完整代码

第三步:对数据做响应式处理,当数据变化时,自动执行更新方法

data 中的每一个属性都会被处理为存取器属性,同时每一个属性都会在闭包中维护一个属于自己的 dep 对象,用于存放该属性的依赖项。当属性被赋予新的值时,就会触发 set 方法,并通知所有依赖项进行更新。

完整代码

Vue 渐进式的特点,使其上手极其容易,我相信,渐进式的展现框架逻辑的实现过程,也会使理解变得更容易。

读懂源码:一步一步实现一个 Vue的更多相关文章

  1. Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码

    在文章:Mybatis源码解析,一步一步从浅入深(一):创建准备工程,中我们为了解析mybatis源码创建了一个mybatis的简单工程(源码已上传github,链接在文章末尾),并实现了一个查询功能 ...

  2. Mybatis源码解析,一步一步从浅入深(一):创建准备工程

    Spring SpringMVC Mybatis(简称ssm)是一个很流行的java web框架,而Mybatis作为ORM 持久层框架,因其灵活简单,深受青睐.而且现在的招聘职位中都要求应试者熟悉M ...

  3. Mybatis源码解析,一步一步从浅入深(三):实例化xml配置解析器(XMLConfigBuilder)

    在上一篇文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码 ,中我们看到 代码:XMLConfigBuilder parser = new XMLConfigBuilder(read ...

  4. Mybatis源码解析,一步一步从浅入深(四):将configuration.xml的解析到Configuration对象实例

    在Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码中我们看到了XMLConfigBuilder(xml配置解析器)的实例化.而且这个实例化过程在文章:Mybatis源码解析,一步一步从浅 ...

  5. Mybatis源码解析,一步一步从浅入深(五):mapper节点的解析

    在上一篇文章Mybatis源码解析,一步一步从浅入深(四):将configuration.xml的解析到Configuration对象实例中我们谈到了properties,settings,envir ...

  6. Mybatis源码解析,一步一步从浅入深(六):映射代理类的获取

    在文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码中我们提到了两个问题: 1,为什么在以前的代码流程中从来没有addMapper,而这里却有getMapper? 2,UserDao ...

  7. Mybatis源码解析,一步一步从浅入深(七):执行查询

    一,前言 我们在文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码的最后一步说到执行查询的关键代码: result = sqlSession.selectOne(command.ge ...

  8. 读jQuery源码 - Deferred

    Deferred首次出现在jQuery 1.5中,在jQuery 1.8之后被改写,它的出现抹平了javascript中的大量回调产生的金字塔,提供了异步编程的能力,它主要服役于jQuery.ajax ...

  9. 读 Zepto 源码之集合元素查找

    这篇依然是跟 dom 相关的方法,侧重点是跟集合元素查找相关的方法. 读Zepto源码系列文章已经放到了github上,欢迎star: reading-zepto 源码版本 本文阅读的源码为 zept ...

随机推荐

  1. LeetCode 292. Nim Game (取物游戏)

    You are playing the following Nim Game with your friend: There is a heap of stones on the table, eac ...

  2. ../../../../.. 太low了

    痛点 如果我们有这个目录: ├── webpack.config.js ├── src │ ├── view │ │ ├── index.js │ │── router │ │ ├── index.j ...

  3. 搭建yeoman自动化构建工具

    yeoman可以快速的搭建一个项目的手脚架,初次接触yeoman,在搭建的过程中遇到了很多的问题. yeoman需要node.js(http://nodejs.org)和git(http://git- ...

  4. JNI 对象处理 (转)

    JNI 的基本问题就是解决 Java 和 C++ 代码互相调用的通信问题,在 C++ 代码编写过程中最大的问题莫过于适应其中的代码编写规则,C++调用或是返回的内容必须遵守 JVM 和 C++ 代码的 ...

  5. 转载——yum源的超级简单配置

    1.先挂载光盘. 使用命令"mount  -o  loop  /dev/sr0 /mnt/cdrom".如果使用命令"mount -o  loop  /dev/cdrom ...

  6. 基于Spring、SpringMVC、MyBatis、Druid、Shrio构建web系统

    源码下载地址:https://github.com/shuaijunlan/Autumn-Framework 在线Demo:http://autumn.shuaijunlan.cn 项目介绍 Autu ...

  7. 我的Spring学习记录(五)

    在我的Spring学习记录(四)中使用了注解的方式对前面三篇做了总结.而这次,使用了用户登录及注册来对于本人前面四篇做一个应用案例,希望通过这个来对于我们的Spring的使用有一定的了解. 1. 程序 ...

  8. 一起写框架-Ioc内核容器的实现-基础功能-getBean(五)

    实现的功能 1. 启动程序时,将@ComponentScan加载的类,创建对象并放在容器里面.(查看上一篇文) 2. 通过ApplicatoinContext的getBean()方法获得容器里面的对象 ...

  9. Qemu 简述

    Qemu 架构 Qemu 是纯软件实现的虚拟化模拟器,几乎可以模拟任何硬件设备,我们最熟悉的就是能够模拟一台能够独立运行操作系统的虚拟机,虚拟机认为自己和硬件打交道,但其实是和 Qemu 模拟出来的硬 ...

  10. Redis Save 与 BGSAVE 的区别

    一,save保存数据到磁盘的方式: Redis Save 命令执行一个同步保存操作,将当前 Redis 实例的所有数据快照(snapshot)以 RDB 文件的形式保存到硬盘. 语法redis Sav ...