前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >「小议」 我从读源码中收获到了什么?阅读源码那点小事

「小议」 我从读源码中收获到了什么?阅读源码那点小事

作者头像
用户6835371
发布2021-06-01 10:39:31
4220
发布2021-06-01 10:39:31
举报
文章被收录于专栏:前端Sharing前端Sharing

一 前言

说到源码,大家脑海里可能浮现出四个字 我太难了???。读源码貌似和我们遥不可及,因为在日常工作中,我们基本掌握在熟练的程度上,就能够满足工作需求,即便是想看源码,也会被源码复杂的逻辑拒之门外,成为了我们心中挥之不去的阴影。那么我们真的有必要阅读源码吗?我以一个过来人的角度看,答案是肯定的,阅读源码不只是停留在源码层面,它还会带来一些附加的价值 。

笔者读过很多源码,比如 主流前端框架 vue2.0,vue3.0 ,reactnode框架 express , koa,和它们衍生生态 react-router,react-redux , dva 等等。要说在阅读源码的过程,痛苦么?我感觉过程是痛苦的,但是读完之后,就会感觉收获颇丰,感觉付出都是值得的。接下来我们一起探讨一下,阅读源码那些事。

二 为什么读源码?

1 为了面试

一场面试题的思考?

假设这是一场面试。

面试官:说一下vue2.0响应式原理 ?

第一位应聘者:object.defineproperty()拦截器属性,拦截set, get

打分:4-5分 这样的答案似乎很难说服我,只能证明面试者对这个知识点有备而来。

第二位应聘者:在第一位基础上,说出了收集依赖的dep对象,负责渲染更新的渲染watcher,递归响应式等等,并能够介绍它们的原理和作用。

打分:6-7分 这样的答案,已经很符合标准了,至少说了vue响应式的核心,说明应聘者至少深入了解过。

第三位应聘者:一方面从初始化 data 开始,到解析 template 模版,进行依赖收集。另一方面能够从 data 改变,通知渲染 watcher 更新,到页面变化,把整个流程说明白。

打分:8-10分 这样的答案,是非常完美的,能够从源码角度入手,说明应聘者很深入原理,读过源码。

从一道面试题,就能看出一个应聘者的对于框架的认知程度。而阅读源码就是从底层开始全方面认识框架的最佳方式。而且如果把源码搞得明明白白。可以让面试官刮目相看。甚至能够‘吊打’面试官??。

2 更清晰的运用框架

阅读源码的过程中,能够了解底层是怎么运作的。如果在工作中遇到某些问题,如果读过源码,就会找到办法,问题也就会迎刃而解。

一个bug案例引发的思考 之前见有同事遇到过这么一个问题。

代码语言:javascript
复制
<el-select v-model="value" >
  <el-option  
    v-for="(item,index) in list" 
    :key="index" 
    :value="item.value"
    :label="item.label"
   />
</el-select>

可能业务场景要比这个复杂,大致是如上这么样的。出现一个问题就是,每次改变 list ,然后重新选择 option 的时候,会发现绑定的 value 数据改变了,但是视图没有发生变化。

如果没有对 vuediff 算法有一定了解,肯定会对这个现象一脸蒙蔽,明明数据已经改变了,但是视图为什么没有变呢?what?

如果看过 diff 算法,和子节点 patch 过程的同学,就会发现,这个问题主要来源于,用 index 作为 key ,在一次更新中,虽然数据改变了,但是根据 index,复用了错误的元素节点,导致了视图和数据不对应的情况。

对于框架或者开源库,如果我们在使用中遇到了问题,与其在 GitHubissue 等待解决,不如亲自去看看源码,也许答案就在其中。正所谓蓦然回首,那人却在灯火阑珊处。

3 提高编程能力,拓展知识盲区

我个人觉得,阅读源码绝对是提高编程能力,拓展知识点的捷径。为什么这么说。我们先看两短经典的代码片段:

no 1 redux compose

代码语言:javascript
复制
export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }
  if (funcs.length === 1) {
    return funcs[0]
  }
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

这是前端领域经典的中间件案例,代码精简,却堪称神来之笔。我们可以学习源码中的,编程手法,即使写不出如上这么经典函数,也能明白什么时候使用继承,什么时候用闭包。

在阅读源码过程中,会有很多高级用法和我们很少用到 api , 我们可以有效对知识点进行扫盲。

no2 vue3.0

vue3.0 /reactivity/src/reactive.ts

代码语言:javascript
复制
const rawToReactive = new WeakMap<any, any>()
const reactiveToRaw = new WeakMap<any, any>()
const rawToReadonly = new WeakMap<any, any>() 
const readonlyToRaw = new WeakMap<any, any>()

vue3.0 中做保存依赖收集关系的几个 WeakMap ,引发了我对 WeakMap 以及垃圾回收机制的思考? WeakMaps 保持了对键名所引用的对象的弱引用,即垃圾回收机制不将该引用考虑在内。只要所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存。也就是说,一旦不再需要, WeakMap 里面的键名对象和所对应的键值对会自动消失,不用手动删除引用。

阅读源码,一方面有助于我们写出诗一样的代码,另一方面,扩充了我们的知识面。总之,真香!

4 培养设计思维和架构能力

优秀的源码有着纵览大局,运筹帷幄的思维,和中流砥柱的架构能力,这对一个正在进阶或者正打算进阶的工程师来说,是最缺少的。

也许你疯狂的补习这知识点,疯狂看这博客,疯狂刷着编程题,但是接手一个大的工程项目的时候,还是会手足无措,最后搞得一塌糊涂。这是为什么呢,也许就真的是缺少那么一丢丢设计思维和架构能力。

人生的三种境界和阅读源码的三种境界是一样的。慢慢的自己编程能力会受到潜移默化的影响。

当你刚开始看源码的时候,看自己的代码还是自己的代码。但是慢慢的,你会发现自己写的代码,受到了源码的影响,已经不像是自己最初的样子,当你日复一日的坚持,你就会明白源码真正架构设计,并能够自己设计架构,代码中有了自己的灵魂,你会发现自己的代码还是自己的代码,原因是自己进步了,能够有能力去把控全局。

三 怎么样读源码

上面讲述了阅读源码的好处,接下来我们讲一讲怎么有效阅读源码。

1 化整为零

冰冻三尺,非一日之寒,阅读源码也不是一朝一夕的事情,我们要有计划的去阅读源码。一天抽出时间看一点,然后重点记笔记,可以是 md,可以是手写的笔记,总之要把核心内容记录下来,因为一是好记性不如烂笔头,可以加深我们的印象。二是在每次阅读之前,都把上一次的笔记拿出来看看,做到完美的衔接。把整个源码分割成多个模块,一点点去消化,不要想着一口气把源码看完,这个是不现实的。

这是笔者在做vue3.0源码阅读解析过程中记录的笔记。

react 源码阅读解析过程中,记录的笔记:

2 三思而后行

这个是笔者阅读源码的精髓所在。三思而后行,在阅读源码的时候先问几个为什么?带着问题去看源码会起到事半功倍的效果,为什么这么说呢?如果不带着问题阅读,就会处于一种无目标,盲目的状态,在这种状态下,尤其看无聊和繁琐的源码,就会精力不集中,长时间就会犯困,无法坚持下去。

在阅读源码之前,首先想几个问题,带着这几个问题去源码中找答案,

例子?一:

vue3.0响应式原理之前,先提几个问题:

  • 1 vue3.0怎么构建的响应式,reactive API到底做了什么?
  • 2 effectreactive 是什么关系?effect 如何取代 watcher ?
  • 3 如何收集的依赖?
  • 4 通过 this.a 改变,是怎么做到视图对应更新的。

例子?二

在阅读 react-redux 的时候,我会先提这么几个问题:

  • 1 为什么要在 root 根组件上使用 react-reduxProvider 组件包裹?
  • 2 react-redux 是怎么和 redux 契合,做到 state 改变更新视图的呢?
  • 3 provide 用什么方式存放当前的 reduxstore, 又是怎么传递给每一个需要订阅 state 的组件的?
  • 4 connect 是怎么样连接我们的业务组件,然后更新已经订阅组件的呢?
  • 5 connect 是怎么通过第一个参数mapStateToProps,来订阅与之对应的 state 的呢?
  • 6 connect 怎么样将 props,和 redux的 state 合并的?

带着这些问题去阅读源码,就会在源码中仔细去寻找这些问题的答案,如果找到了答案,并解释了原理,也会有不错的成就感。

3 提炼精髓

这一步对于阅读源码也是非常重要的,我们要学会提炼源码的精髓,以 react 为例子,react 个别函数,可能几百行,甚至上千行,但是除去服务端渲染,开发环境的警告 __dev__ ,context 上下文的处理,和一些判断等等,真正的核心逻辑代码,也许就那么几行和十几行,所以我们不需要去扣源码中的每一行代码,只需要搞清楚核心逻辑就好。

我们拿react源码为例子:

react/react-reconciler/ReactFiberClassComponent.js

这个文件下,有一个 constructClassInstance 方法,用于 new 我们的组件实例。这个方法大约有 200 行左右,但是我给它进行提炼之后,代码如下

代码语言:javascript
复制
function constructClassInstance(
  workInProgress, // 
  ctor,    // 我们的 component 
  props,  //  组件的 props 
){
  /* 这里实例化 我们的component */
  const instance = new ctor(props, context);
  /* 给当前 组件实例 ,挂上 updater 对象,用于组件渲染更新 */   
  adoptClassInstance(workInProgress, instance);
}

核心的代码只有这区区几行,所以在阅读源码的流程中,提炼精髓也是十分重要的。

4 真枪实弹

实践是检验真理的唯一标准。如果想搞清楚源码,不要单独停留在看的层面,也要真正去跑一遍源码。这样一来我们可以在 github ,克隆下来源码。然后在关键的上下文,可以 debugger 或者 console

步骤如下:

github 下载文件。

然后进行debugger或者 console。

接下来把源码单独抽出来,打包。

放入我们的demo项目进行验证。

此时我们要改变一下路径。因为原来我们的 package 是放在 node_modules 中的,现在路径改了,所以注意路径问题。

5 因材施教

并不是所有的框架源码都需要一个固定的模式去解析的。这一点笔者就吃了苦头。我们先来说一下背景。

笔者在阅读 vue2.0,采用集中式阅读,就是从new Vue为入口,然后逐步向代码深层去挖掘。最后将各个模块串联起来。

在阅读完vue2.0的核心原理后, 想要以同样的模式去阅读 react,发现此方案根本行不通,因为react 有很多模块,比如 react, react-reconciler ,react-dom,scheduler,有好几千个函数方法,看着看着就蒙蔽了,即使 debugger ,效果也是甚微,无法把各模块功能串联起来,形成体系。

后来,开始阅读一些大佬的文章,先明白每一块干了些什么,有什么作用,然后一块块的串起来。最后再去阅读源码,发现效果甚佳。

案例: vuereact

vue 集中式阅读源码

vue 源码适合集中式阅读,就是从 new vue() 开始,到初始化 data ,建立响应式 ,patch 元素节点,解析 template 模版,注入依赖,挂载真实 dom ,一气呵成,一条线串起来。

react 发散式阅读源码

react 需要一种发散式的阅读方法,就是你需要先明白,reconciler,scheduler,expiration time,请求关键帧等等,具体是干什么的,有什么作用,然后像搭积木一样,把它们搭起来。

6 水滴石穿

把值得做的事坚持下去,再把坚持做的事努力做好。 既然选择阅读源码,就要坚持下去,笔者刚开始看源码的时候也是很痛苦,曾经几度想放弃,但是后来按照上面方法,坚持下去,终于养成了好习惯,现在完全能够注意力集中的阅读源码,而且过程感觉也不像当初那么无趣。

听说过21天效应,如果一天一天坚持下去,用不了多久就能养成一种阅读源码的好习惯,相信那个时候,我们比如尝试用一个新的 package 的时候,忍不住先去 github 上拉下源码瞧瞧。

四 收获与总结

关于收获

看源码的习惯坚持了差不多二年了,收获感觉还是蛮多的,首先无论是从知识储备还是编程写法或者设计架构上,都有很大的进步,也尝试了写了自己的开源项目,并下定决心好好维护下去。

rux 一款redux和react-redux状态管理工具

react-keepalive-router缓存页面路由

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-03-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端Sharing 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一 前言
  • 二 为什么读源码?
    • 1 为了面试
      • 2 更清晰的运用框架
        • 3 提高编程能力,拓展知识盲区
          • 4 培养设计思维和架构能力
          • 三 怎么样读源码
            • 1 化整为零
              • 2 三思而后行
                • 3 提炼精髓
                  • 4 真枪实弹
                    • 5 因材施教
                      • 6 水滴石穿
                      • 四 收获与总结
                      相关产品与服务
                      消息队列 TDMQ
                      消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档