现如今我们的开发工作并不会从零开始,往往会基于很多开源库,就前端而言,构建工具我们会使用 webpack,MVVM 框架我们会使用 Vue、React 或者 Angular,这些开源工具帮助我们大大提升了生产效率。
通常我们学习一个开源项目的步骤都是先去阅读它的官方文档,下载安装后运行它的一些 demo 实例,然后在工作中去应用和踩坑。当我们对一个开源项目熟练使用并掌握后,再想去深入了解它就需要去阅读它的源码了。
很多同学都尝试学习过源码,目前业内也会有各种开源库的源码解析文章,那么今天我们也来聊聊源码学习这个事儿。
为什么做
为什么大家对源码解析这个事情乐此不彼呢,或者说我们为什么要去学习源码呢,通常有以下几个原因:
兴趣驱动
这样的同学往往是对技术非常热爱,对未知技术的探索有着非常大的兴趣,喜欢刨根问底。因此对于优秀的开源项目,他们都会非常愿意花时间去探究它的实现原理,并且一旦弄明白后会有非常大的成就感。
技术驱动
这样的同学往往是愿意通过更多的学习来提升自己的技术能力。造轮子的技术含量比使用轮子的技术含量高,那么研究轮子的实现原理,知道这个轮子是如何造出来的,也能在很大程度上提升自己的技术能力。而且一般研究的源码都是和工作相关,学习源码也可以很好辅助自己平时的工作开发。
坑驱动
这样的同学会在使用开源项目过程中踩到一些坑,并且查阅资料无果后决定来看一下源码的实现,去找一下问题的原因。但是坑驱动学习源码的方式比较被动,往往只能学习到源码的冰山一角,效果不如前 2 者。
面试驱动
这样的同学可能占比最高,因为如今很多面试官都喜欢问一些技术的实现原理,那么就会逼迫大家在面试前去学习平时工作中使用到技术栈的原理实现,但是这样的学习是最被动的,很多人可能选择去看一些源码解析的文章去死记硬背,而并没有真正掌握源码实现的精髓。
什么时候做
学习源码固然是件好事,但是如果在了不恰当的时机去学习可能会适得其反。有一部分同学对一个开源项目甚至都没搞清楚是干什么的时候就开始去看源码了,如果是一些稍微复杂的开源项目,这样的效率非常低下的,很大概率是时间浪费了什么也没有学到。
那么什么时候我们该学习源码呢,我认为你至少已经对这个开源项目的使用已经很熟练了,并且对它的设计思想,用来解决什么问题等等都比较清楚的时候,为了进一步对它深入学习,就可以来看它的源码实现了。
怎么做
那么如何去学习源码就非常重要了,诚然学习源码是一定会花时间的,好的学习方法会大大提升学习效率,事半功倍。其实社区也有人推荐了一些学习源码的方式,比如说从源码早期的 commit 开始看,仿造一个小型轮子等等。这里我结合自己看源码的经验总结了几个点。
全盘了解
首先你要对这个开源项目要有全盘的了解,知道它产生的背景,来解决什么样的问题。开始看源码前,先对它的源码目录结构、代码执行入口、构建打包方式、最终产出的文件等等有一个整体的了解。需要用一个全局的视野去审视源码,切忌漫无目的的看源码。
问题驱动
在全盘了解的基础上,就可以通过问题驱动去看源码了。以 Vue.js 为例,我们知道了它的核心思想是数据驱动 + 组件化,那么我们就可以问自己,Vue 模板的数据是如何渲染到 DOM 上的,数据更新后模板是如何重新渲染的,组件化是如何实现的,模板到 render 函数如何编译的等等。那么每一个问题都可以值得我们针对性地去学习源码。问题驱动的方式和坑驱动不同的地方在于这个学习过程是主动的,自驱的,学到的东西会更加系统和全面;而坑驱动往往都会满足于解决某个问题就停下了,学习会比较局限。
主线优先
当我们通过问题驱动去看代码的时候,要牢记主线优先,所谓主线就是解决你这个问题核心流程中的代码。因为通常一个开源项目它的功能会很丰富,所以代码分支逻辑会有很多。而当我们带着问题去看源码的时候,切忌像代码执行一样把每个分支逻辑都去看一遍,我们要关心的就是主线部分。分支逻辑通常都是为了解决某些特定场景的问题,那么如果想学习它的话就针对这个场景分析的时候再回来看即可。还是以 Vue.js 为例,比如我们在分析模板是如何驱动 DOM 渲染的,我们只要关心核心流程 init -> mount -> render -> update -> patch 这个过程的实现即可。那么过程中遇到的初始化响应式对象这些分支逻辑,我们就可以先不看,因为当前分析的这个场景并不会有数据更新的部分,而这部分内容我们可以放到深入研究响应式原理的时候再看。
参与共建
我理想中的开源社区是有更多的人参与到开源项目的共建中,当我们给开源项目做贡献的时候,会要求我们对源码的理解要更加深入。共建的方式有多种,比如可以给开源项目提个 pr;比如主动要求帮助解决开源项目现有的 issue;比如参与开源项目的文档编写工作等等。我在研究 Vue.js 源码的过程中,也发现了一处源码的实现和文档不符的情况,于是提了 pr 对这个文档做了修复。通过共建的方式不仅仅可以帮助我们学习源码,也能增加成就感,一举两得。
阅读技巧
当然,阅读源码也是有很多技巧的,比如关键地方加断点单步调试、复杂函数看单元测试的输入输出、复杂逻辑通过画图辅助等等。
辅助资料
看懂源码实际上是一个有挑战的过程,特别是一个复杂的开源项目。不同水平的人可能对源码的理解程度不一样,这时候如果有一些别人分析好的优秀资料辅助我们学习源码,那么效率会大大提升,理解起来也会更加容易。但是社区源码分析的资料很多,如何鉴别好的资料是非常有必要的。
Vue.js 作为前端 MVVM 框架,已经被越来越多的公司使用,各类的源码分析文章也层出不穷。但是纵观这些源码分析文章,大部分都是作者的一些学习笔记,通过给源码加一些注释的方式,这种资料和直接去看源码差别并不大,因为源码也会在一些需要的地方加上注释(除非你英文很差看不懂)。另一个比较大的问题就是比较零散,不够系统和全面,如果想完整地去学习 Vue.js,这种东拼西凑的学习资料其实效果也并不好。但是社区也有做的不错的,比如染陌同学的 learnVue,算是我见到的比较全面的 Vue.js 源码分析系列文章了。
由于我平时的工作项目就是利用 Vue.js 开发的,所以对 Vue.js 的研究也算比较多。我之前在慕课网上做过 2 门 Vue.js 的实战课程,第一门《 Vue.js 高仿饿了么》课程帮助大家入门了 Vue.js,第二门 《Vue.js 音乐 App》课程帮助大家在 Vue.js 的实战方面做了进阶。去年第二门课程出了后,我就在思考一件事,如何帮助我的学生在 Vue.js 这个方向继续提升。于是我想到了做一门 《Vue.js 源码解析》的课程,帮助同学们修炼内功。
市面上还没有源码解析类的视频教学课程,我是第一个吃螃蟹的,源码课程的录制难度要远大于实战课程的录制,从开始准备到课程上线,经历了半年以上的时间。为了把 Vue.js 的源码讲明白,我结合了自己读源码的经验,把课程设计成由浅入深,分为核心、编译、扩展、生态四个方面去讲,并拆成了八个章节,如下图:
[图片上传失败...(image-2c8a6-1536313206324)]
第一章:准备工作
介绍了 Flow、Vue.js 的源码目录设计、Vue.js 的源码构建方式,以及从入口开始分析了 Vue.js 的初始化过程。
第二章:数据驱动
详细讲解了模板数据到 DOM 渲染的过程,从 new Vue
开始,分析了 mount
、render
、update
、patch
等流程。
第三章:组件化
分析了组件化的实现原理,并且分析了组件周边的原理实现,包括合并配置、生命周期、组件注册、异步组件。
第四章:深入响应式原理
详细讲解了数据的变化如何驱动视图的变化,分析了响应式对象的创建,依赖收集、派发更新的实现过程,一些特殊情况的处理,并对比了计算属性和侦听属性的实现,最后分析了组件更新的过程。
第五章:编译
从编译的入口函数开始,分析了编译的三个核心流程的实现:parse
-> optimize
-> codegen
。
第六章:扩展
详细讲解了 event
、v-model
、slot
、keep-alive
、transition
、transition-group
等常用功能的原理实现,该章节作为一个可扩展章节,未来会分析更多 Vue 提供的特性。
第七章:Vue-Router
分析了 Vue-Router 的实现原理,从路由注册开始,分析了路由对象、matcher
,并深入分析了整个路径切换的实现过程和细节。
第八章:Vuex
分析了 Vuex 的实现原理,深入分析了它的初始化过程,常用 API 以及插件部分的实现。
结语
通常我们对一门技术的掌握程度,我把它分为了 5 个层次:会用;熟练掌握;了解其实现原理;知道为什么这么做;能提出更好的实现方式。相信大部分同学还在前 2 个层次,那么对源码的学习,可以让我们进阶到第 3 个层次。如果你达到了第 4 个层次以上,那么你已经是一个技术专家了。
希望同学们在学习源码的同时,不仅仅知其然,也能知其所以然。