摘要:精讀原文介紹了學(xué)習(xí)源碼的兩個(gè)技巧,并利用實(shí)例說明了源碼學(xué)習(xí)過程中可以學(xué)到許多周邊知識(shí),都讓我們受益匪淺。討論地址是精讀源碼學(xué)習(xí)如果你想?yún)⑴c討論,請(qǐng)點(diǎn)擊這里,每周都有新的主題,周末或周一發(fā)布。
1. 引言
javascript-knowledge-reading-source-code 這篇文章介紹了閱讀源碼的重要性,精讀系列也已有八期源碼系列文章,分別是:
精讀《Immer.js》源碼
精讀《sqorn 源碼》
精讀《Epitath 源碼 - renderProps 新用法》
精讀《Htm - Hyperscript 源碼》
精讀《React PowerPlug 源碼》
精讀《syntax-parser 源碼》
精讀《react-easy-state 源碼》
精讀《Inject Instance 源碼》
筆者自己的感悟是,度過大量源碼的程序員有以下幾個(gè)特質(zhì):
思考具有系統(tǒng)性,主要體現(xiàn)在改一處代碼模塊時(shí),會(huì)將項(xiàng)目所有文件串聯(lián)起來整體考慮,提前評(píng)估影響面。
思考具有前瞻性,對(duì)已實(shí)現(xiàn)的方案可以快速評(píng)價(jià)所處階段(臨時(shí) or 標(biāo)準(zhǔn) or 可拓展),將邊界情況提前解決,將框架 BUG 降低到最小程度。
代碼實(shí)現(xiàn)更優(yōu)雅,有大量源碼經(jīng)驗(yàn)做支撐,解決同樣問題時(shí),這些程序員可以用更短的行數(shù)、更合適的三方庫解決問題,代碼可讀性更好,模塊拆分更合理,更利于維護(hù)。
既然閱讀源碼這么重要,那么怎么才能讀好源碼呢?本周精讀的文章就是一篇方法論文章,告訴你如何更好的閱讀源碼。
2. 概述原文分三個(gè)部分:閱讀源碼的好處、閱讀源碼的技巧、以及 Redux Connect 的案例研究。
閱讀源碼的好處閱讀源碼有助于理解抽象的概念,比如虛擬 DOM;有助于做方案調(diào)研,而不僅僅只看 Github star 數(shù)量;了解優(yōu)秀框架目錄結(jié)構(gòu)的設(shè)計(jì);看到一些陌生的工具函數(shù),還可能激發(fā)你對(duì) JS 規(guī)范的查閱,這種問題驅(qū)動(dòng)的方式也是筆者推薦的 JS 規(guī)范學(xué)習(xí)方式。
閱讀源碼的技巧最好的閱讀源碼方式是看文章,如果源碼的作者有寫源碼解讀文章,這就是最省力的方式。雖然直接看代碼可以了解到所有細(xì)節(jié),但當(dāng)你不清楚設(shè)計(jì)思路時(shí),僅看源碼可能會(huì)找不到方向,而讀源碼的最終目的是找到核心的設(shè)計(jì)理念,如果一個(gè)框架沒有自己核心設(shè)計(jì)理念,這個(gè)框架也不值得誕生,更不值得被閱讀。如果框架的作者已經(jīng)將框架核心理念寫成了文章,那讀文章就是最佳方案。
還有一種方式是斷點(diǎn),寫一個(gè)最小程序,在框架執(zhí)行入口出打下斷點(diǎn),然后按照?qǐng)?zhí)行路徑一步步理解。雖然執(zhí)行路徑中會(huì)存在大量無關(guān)的函數(shù)干擾精力,但如果你足夠有耐心,當(dāng)斷點(diǎn)走完時(shí)一定會(huì)有所收獲。
原文還提到了一種看源碼方式,即沒有目的的尋寶。在尋找框架主要思路的過程中,遇到一些有意思的函數(shù),可以停下來仔細(xì)閱讀,可能會(huì)發(fā)現(xiàn)一些對(duì)你有啟發(fā)的代碼片段。
Redux Connect 案例研究原文以 Redux Connect 作為案例介紹研究思路。
首先看到 Connect 的功能 “包裝組件” 后,就要問自己兩個(gè)問題:
Connect 是如何實(shí)現(xiàn)包裝組件后原樣返回組件,但卻增強(qiáng)組件功能的?(高階組件知識(shí))
了解這個(gè)設(shè)計(jì)模式后,如何利用已有的文檔實(shí)現(xiàn)它?
通過創(chuàng)建一個(gè)使用 Connect 的基本程序:
class MarketContainer extends Component { } const mapDispatchToProps = dispatch => { return { updateSummary: (summary, start, today) => dispatch(updateSummary(summary, start, today)) } } export default connect(null, mapDispatchToProps)(MarketContainer);
比如從生成 connect 函數(shù)的 createConnect 我們就可以學(xué)習(xí)到 Facade Pattern - 門面模式。
從 createConnect 函數(shù)調(diào)用處:
export function createConnect({ connectHOC = connectAdvanced, mapStateToPropsFactories = defaultMapStateToPropsFactories, mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories, mergePropsFactories = defaultMergePropsFactories, selectorFactory = defaultSelectorFactory } = {})
我們可以學(xué)習(xí)到解構(gòu)默認(rèn)函數(shù)參數(shù)的知識(shí)點(diǎn)。
總之,在學(xué)習(xí)源碼的過程中,可以了解到一些新的 JS 特性,一些設(shè)計(jì)模式,這些都是額外的寶藏,不斷理解并學(xué)會(huì)運(yùn)用到自己寫的框架里,就實(shí)現(xiàn)了源碼學(xué)習(xí)的目的。
3. 精讀原文介紹了學(xué)習(xí)源碼的兩個(gè)技巧,并利用 Redux Connect 實(shí)例說明了源碼學(xué)習(xí)過程中可以學(xué)到許多周邊知識(shí),都讓我們受益匪淺。
筆者結(jié)合之前寫過的八篇源碼分析文章,把最重要的設(shè)計(jì)思路提取出來,以實(shí)際的例子展示閱讀源碼能給我們思維帶來哪些幫助。
Immerjs 源碼的精華Immer 可以讓我們以 Mutable 的方式更新對(duì)象,最終得到一個(gè) Immutable 對(duì)象:
this.setState(produce(state => (state.isShow = true)))
詳細(xì)源碼解讀可以閱讀 這里。
核心思路是利用 Proxy 把臟活累活做掉。上面的例子中,state 已經(jīng)是一個(gè)代理(Proxy)對(duì)象,通過自定義 setting 不斷遞歸進(jìn)行淺拷貝,最后返回一個(gè)新引用的頂層對(duì)象作為 produce 的返回值。
從 Immerjs 中,我們學(xué)到了 Proxy 可以化腐朽為神奇的用法,比看任何 Proxy 介紹文章都直觀。
sqorn 源碼的精華sqorn 是一個(gè) sql orm,舉例來看:
const sq = require("sqorn-pg")(); const Person = sq`person`, Book = sq`book`; // SELECT const children = await Person`age < ${13}`; // "select * from person where age < 13"
詳細(xì)源碼解讀可以閱讀 這里
核心思路是在鏈?zhǔn)秸{(diào)用過程中創(chuàng)建 context 存儲(chǔ)結(jié)構(gòu),并在鏈?zhǔn)秸{(diào)用的時(shí)候不斷填充 context 信息,最終拿到的是一個(gè)結(jié)構(gòu)化 context 對(duì)象,生成 sql 語句也就簡單了。
從 sqorn 中,我們學(xué)到了如何實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用 init().a().b().c().print() 最后拿到一個(gè)綜合的結(jié)果,原理是內(nèi)部維護(hù)了一個(gè)不斷修改的對(duì)象。不論前端 React Vue 還是后端框架 Koa 等,一般都有內(nèi)置的 context,一般實(shí)現(xiàn)這種優(yōu)雅語法的框架內(nèi)部都會(huì)維護(hù) context。
Epitath 源碼的精華Epitath 在 React Hooks 之前出來,解決了高階函數(shù)地獄的問題:
const App = epitath(function*() { const { count } = yieldconst { on } = yield return ( ) })
詳細(xì)源碼解讀可以閱讀 這里
其核心是利用 generator 的迭代,將 React 組件的平級(jí)結(jié)構(gòu)還原成嵌套結(jié)構(gòu),將嵌套寫法打平了:
yield yield yield// 等價(jià)于
從 epitath 中,我們了解到 generator 原來可以這么用,正因?yàn)槠鋱?zhí)行是多次迭代的,因此我們可以利用這個(gè)特性,改變代碼運(yùn)行結(jié)構(gòu)。
Htm - Hyperscript 源碼的精華Htm 將模版語法很自然的融入到了 html 中:
html`<${Header} name="ToDo"s (${page})" />`;${todos.map( todo => html`
<${Footer}>footer content here/>- ${todo}
` )}
詳細(xì)源碼解讀可以閱讀 這里
其核心是怎么根據(jù)模版拿到 dom 元素的 AST?拿到 AST 后就方便生成后續(xù)內(nèi)容了。
作者的辦法是:
const TEMPLATE = document.createElement("template"); TEMPLATE.innerHTML = str;
這樣 TEMPLATE 就自帶了 AST 解析,這是利用瀏覽器自帶的 AST 解析拿到了 AST。從 Htm 中,我們學(xué)到了 innerHTML 可以生成標(biāo)準(zhǔn) AST,所以只要有瀏覽器運(yùn)行環(huán)境,需要拿 AST 的時(shí)候,不需要其他庫,innerHTML 就是最好的方案。
React PowerPlug 源碼的精華React PowerPlug 是一個(gè)利用 render props 進(jìn)行狀態(tài)管理的工具庫。
它可以在 JSX 中對(duì)任意粒度插入狀態(tài)管理:
{({ value, set, reset }) => ( <> > )}
詳細(xì)源碼解讀可以閱讀 這里
這個(gè)庫的核心就是利用 render props 解決 JSX 局部狀態(tài)管理的痛點(diǎn),通過讀源碼了解 render props 的使用方式是這個(gè)源碼帶給你的最大價(jià)值。
syntax-parser 源碼的精華syntax-parser 是一個(gè) JS 版語法解器生成器,筆者也是作者,使用方式:
import { createParser, chain, matchTokenType, many } from "syntax-parser"; const root = () => chain(addExpr)(ast => ast[0]); const addExpr = () => chain(matchTokenType("word"), many(addPlus))(ast => ({ left: ast[0].value, operator: ast[1] && ast[1][0].operator, right: ast[1] && ast[1][0].term })); const addPlus = () => chain("+"), root)(ast => ({ operator: ast[0].value, term: ast[1] })); const myParser = createParser( root, // Root grammar. myLexer // Created in lexer example. );
詳細(xì)源碼解讀可以閱讀 這里
syntax-parser 的核心是利用雙向鏈表實(shí)現(xiàn)了可回溯的語法解析器,了解了這個(gè)庫,你可以自己實(shí)現(xiàn) JS 調(diào)用堆棧,并在任意時(shí)候返回某個(gè)之前的執(zhí)行狀態(tài)重新執(zhí)行。同時(shí)這個(gè)庫的源碼也會(huì)加強(qiáng)你對(duì)鏈表的理解,以及拓展你對(duì)鏈表使用場(chǎng)景的想象。
react-easy-state 源碼的精華react-easy-state 利用 Proxy 創(chuàng)建了一個(gè)簡易的全局?jǐn)?shù)據(jù)流管理方式:
import React from "react"; import { store, view } from "react-easy-state"; const counter = store({ num: 0 }); const increment = () => counter.num++; export default view(() => );
詳細(xì)源碼解讀可以閱讀 這里
react-easy-state 利用了 observer-util 實(shí)現(xiàn)主要功能,從中我們能學(xué)到最有價(jià)值的就是 Proxy 與 React 結(jié)合的設(shè)計(jì)理念,即利用 getter setter 實(shí)現(xiàn)數(shù)據(jù)與視圖的雙向綁定,或者叫依賴追蹤,更多細(xì)節(jié)就不在這里展開,感興趣可以閱讀筆者之前寫的 抽絲剝繭,實(shí)現(xiàn)依賴追蹤 一節(jié)。
Inject Instance 源碼的精華inject-instance 是一個(gè) Class 實(shí)現(xiàn)依賴注入的庫:
import {inject} from "inject-instance" import B from "./B" class A { @inject("B") private b: B public name = "aaa" say() { console.log("A inject B instance", this.b.name) } }
詳細(xì)源碼解讀可以閱讀 這里
主要對(duì)我們有兩個(gè)啟發(fā),第一可以利用裝飾器為對(duì)象存儲(chǔ)一些額外信息,這些信息在必要的時(shí)候我們可以用到;第二是依賴注入并不復(fù)雜,通過提前實(shí)例化后,可以解決循環(huán)依賴的問題,即所有循環(huán)依賴問題都可以通過加一個(gè)父級(jí)解決。
4. 總結(jié)閱讀代碼不是目的,讀懂源碼背后要表達(dá)的核心設(shè)計(jì)思路才是目的。比如寫腳手架,閱讀了大量腳手架源碼的人寫出的代碼,與一個(gè)沒有經(jīng)驗(yàn)的人寫出的代碼會(huì)有天壤之別,這之間的差距就是對(duì)一些設(shè)計(jì)模式、三方庫、結(jié)構(gòu)設(shè)計(jì)的經(jīng)驗(yàn)差距。
只學(xué)習(xí)理論太空洞,只看代碼又太局限,學(xué)會(huì)從代碼中看出理論才是最佳學(xué)習(xí)方式。
討論地址是:精讀《源碼學(xué)習(xí)》 · Issue #179 · dt-fe/weekly
如果你想?yún)⑴c討論,請(qǐng) 點(diǎn)擊這里,每周都有新的主題,周末或周一發(fā)布。前端精讀 - 幫你篩選靠譜的內(nèi)容。
關(guān)注 前端精讀微信公眾號(hào)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/105851.html
摘要:精讀源碼一共行,我們分析一下其精妙的方式。更多討論討論地址是精讀新用法如果你想?yún)⑴c討論,請(qǐng)點(diǎn)擊這里,每周都有新的主題,周末或周一發(fā)布。前端精讀幫你篩選靠譜的內(nèi)容。 1 引言 很高興這一期的話題是由 epitath 的作者 grsabreu 提供的。 前端發(fā)展了 20 多年,隨著發(fā)展中國家越來越多的互聯(lián)網(wǎng)從業(yè)者涌入,現(xiàn)在前端知識(shí)玲瑯滿足,概念、庫也越來越多。雖然內(nèi)容越來越多,但作為個(gè)體的...
摘要:引言前端精讀手寫編譯器系列介紹了如何利用生成語法樹,而還有一些庫的作用是根據(jù)語法樹生成語句。對(duì),有利就有弊,這些庫不遵循語法樹,但利用簡化的對(duì)象模型快速生成,使得代碼抽象程度得到了提高。 1 引言 前端精讀《手寫 SQL 編譯器系列》 介紹了如何利用 SQL 生成語法樹,而還有一些庫的作用是根據(jù)語法樹生成 SQL 語句。 除此之外,還有一種庫,是根據(jù)編程語言生成 SQL。sqorn 就...
showImg(https://segmentfault.com/img/bVbw3tK?w=1240&h=827); 前端工程師這個(gè)崗位,真的是反人性的 我們來思考一個(gè)問題: 一個(gè)6年左右經(jīng)驗(yàn)的前端工程師: 前面兩年在用jQuery 期間一直在用React-native(一步一步踩坑過來的那種) 最近兩年還在寫微信小程序 下面一個(gè)2年經(jīng)驗(yàn)的前端工程師: 并不會(huì)跨平臺(tái)技術(shù),他的兩年工作都是Reac...
摘要:會(huì)自動(dòng)觸發(fā)函數(shù)內(nèi)回調(diào)函數(shù)的執(zhí)行。因此利用并將依賴置為使代碼在所有渲染周期內(nèi),只在初始化執(zhí)行一次。同時(shí)代碼里還對(duì)等公共方法進(jìn)行了包裝,讓這些回調(diào)函數(shù)中自帶效果。前端精讀幫你篩選靠譜的內(nèi)容。 1. 引言 react-easy-state 是個(gè)比較有趣的庫,利用 Proxy 創(chuàng)建了一個(gè)非常易用的全局?jǐn)?shù)據(jù)流管理方式。 import React from react; import { stor...
摘要:今天,我我的后端書架后端掘金我的后端書架月前本書架主要針對(duì)后端開發(fā)與架構(gòu)。尤其是對(duì)稱加密,非對(duì)稱加密,私鑰加密,公鑰加密滴滴動(dòng)態(tài)化方案的誕生與起航掘金這是滴滴架構(gòu)組發(fā)布的第一篇公共技術(shù)文章,本文將介紹自研的動(dòng)態(tài)化方案。 android 阿里面試題錦集 - Android - 掘金前幾天突然就經(jīng)歷了阿里android實(shí)習(xí)內(nèi)推的電面,感覺有好多以前看過的東西都忘記了,然后又復(fù)習(xí)了一下,找了...
閱讀 2594·2021-09-02 15:40
閱讀 1592·2019-08-30 15:54
閱讀 1114·2019-08-30 12:48
閱讀 3430·2019-08-29 17:23
閱讀 1067·2019-08-28 18:04
閱讀 3688·2019-08-26 13:54
閱讀 634·2019-08-26 11:40
閱讀 2432·2019-08-26 10:15