讀懂源碼:一步一步實現一個 Vue


源碼閱讀:究竟怎樣才算是讀懂了?

市面上有很多源碼分析的文章,就我看到的而言,基本的套路就是梳理流程,講一講每個模塊的功能,整篇文章有一大半都是直接掛源碼。我不禁懷疑,作者真的看懂了嗎?為什么我看完后還是什么都不懂呢?

事實上一個經過無數次版本迭代的框架源碼並不適合初學者直接閱讀,因為里面有太多細節,太多噪點,太多枝枝蔓蔓。要想真正理解框架的核心邏輯,必須剝繭抽絲,還原出一個純凈的雛形。如同 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 漸進式的特點,使其上手極其容易,我相信,漸進式的展現框架邏輯的實現過程,也會使理解變得更容易。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM