javascript基礎修煉(10)——VirtualDOM和基本DFS

来源:https://www.cnblogs.com/dashnowords/archive/2018/11/29/10030036.html
-Advertisement-
Play Games

1. Virtual DOM是什麼 Virtual DOM,即虛擬DOM樹。瀏覽器在解析文件時,會將 文檔轉換為 對象,在瀏覽器環境中運行的腳本文件都可以獲取到它,通過操作 對象暴露的介面可以直接操作頁面上的DOM節點。但是DOM讀寫是非常耗性能的,很容易觸發不必要的重繪和重排,為了更好地處理DOM ...


1. Virtual-DOM是什麼

Virtual-DOM,即虛擬DOM樹。瀏覽器在解析文件時,會將html文檔轉換為document對象,在瀏覽器環境中運行的腳本文件都可以獲取到它,通過操作document對象暴露的介面可以直接操作頁面上的DOM節點。但是DOM讀寫是非常耗性能的,很容易觸發不必要的重繪和重排,為了更好地處理DOM操作,Virtual-DOM技術就誕生了。Virtual-DOM就是在javascript中模擬真實DOM的結構,通過數據追蹤和狀態對比來減少對於真實DOM的操作,以此來提高程式的效率的一種技術。

Virtual-DOM技術是前端高性能的基石,它是真實document對象的抽象,通過對比新舊Virtual-DOM的區別,找出發生變化的DOM節點,再利用演算法得到相對更合理的DOM節點修改方案,最終再將方案應用在document對象上來改變頁面的展示內容。

主流前端SPA框架都離不開【Virtual-DOM模型 + DOM-Diff演算法 + 生命周期鉤子】這樣的核心模型。

2. Virtual-DOM的基本結構

在上一篇博文《javascript基礎修煉(9)——MVVM中雙向數據綁定的基本原理》中,我們通過document.getElementById()從真實DOM中獲得了帶有自定義屬性的待解析結構,這裡是有一些問題的,實際的過程是先解析模板字元串得到虛擬DOM樹,最後生成真實的DOM樹。

實際上我們在使用SPA框架時所編寫的html模板,並沒有被直接當做DOM片段載入到頁面上使用,而是將文件當做字元串讀入到程式中,然後通過解析來生成Virtual-DOM樹,接著通過SPA框架的渲染函數來生成必要的片段後才生成真實的DOM節點。例如我們要生成下文示例的HTML片段(為了方便演示,示例中只涉及了類名和文本節點):

<body class="main">
   <div class="sideBar">
       <ul class="sideBarContainer">
           <li class="sideBarItem">sidebar-1</li>
           <li class="sideBarItem">sidebar-2</li>
           <li class="sideBarItem">sidebar-3</li>
       </ul>
   </div>
   <div class="mainContent">
        <div class="header">header-zone</div>
        <div class="coreContent">core-content</div>
        <div class="footer">footer-zone</div>
   </div>
   <div class="rightSide">暫未開發</div>
</body>

我們需要構建出一個簡易模型來表達上面的結構:

virtualDom = {
    name:"body",
    props:{
        className:"main"
    },
    children:[{
        name:"div",
        props:{...},
        children:[...]
      },{
        name:"div",
        props:{...},
        children:[...]
      },{
        name:"div",
        props:{...},
        children:[...]
      }]
}

建立一個生成虛擬節點的輔助函數:

//構建DOM節點的輔助函數
function h(name, props, children) {
    return {
        name:name,
        props:props,
        children:children
    }
}
//手動生成virtual-DOM
var tree = h('body',{className:'main'},[
       h('div',{className:'sideBar'},[
          h('ul',{className:'sideBarContainer'},[
               h('li',{className:'sideBarItem'},['sidebar-1']),
               h('li',{className:'sideBarItem'},['sidebar-2']),
               h('li',{className:'sideBarItem'},['sidebar-3']),
            ])
        ]),
       h('div',{className:'mainContent'},[
           h('div',{className:'header'},['header-zone']),
           h('div',{className:'coreContent'},['core-content']),
           h('div',{className:'footer'},['footer-zone']),
        ]),
       h('div',{className:'rightSide'},['暫未開發'])
    ]);

通過上面的方法得到的tree對象就涵蓋了模板片段中的結構和關鍵信息。實際開發中並不需要像上面一樣手動來填寫DOM結構,可以將模板字元串掛載到離線DOM節點上,然後在遞歸解析的同時來構建Virtual-DOM就可以了。

3. 使用DFS從Virtual-DOM生成DOM

至此我們完成了模板的編譯,也得到了Virtual-DOM對象,但它似乎並沒有什麼用處,畢竟我們已經完成了對模板的解析,渲染出頁面沒什麼問題,其實Virtual-DOM對於首屏來說並沒有什麼特別重要的意義,它的價值在模型和視圖發生變化時才會體現。上一篇博文的末尾我們已經提到了更新視圖時的效率問題,當數據模型發生變化後,我們需要一個方法來收集所有需要修改的DOM,併為之提供高效的修改方式(你總不能一有變化就把整個網頁重新渲染,或者讓數據模型各自去修改各自綁定的DOM吧)。那麼為了能夠收集所有DOM節點的變化,我們就需要遍歷所有節點。

對數據結構和演算法有一定瞭解的讀者很容易想到,遍歷解析一個Virtual-DOM實際上就是對其進行先序深度優先遍歷(Pre-Order Depth-First-Search),本節中,我們先預熱一下,使用這種方式來複現一下DOM結構。

function dfswalking(tree) {
    var _childrenLength;
    //執行動作
    if (typeof tree.children[0] === 'string') {
        console.log(`<${tree.name} class="${tree.props.className}">${tree.children[0]}</${tree.name}>`);
    } else {
        console.log(`<${tree.name} class="${tree.props.className}">  -->`);
        for(var i = 0, _childrenLength = tree.children.length; i < _childrenLength; i++){
            dfswalking(tree.children[i]);
        }
    }
}

本例中僅列印出字元串的方式來展示,可以在控制台看到輸出結果:

下一篇博文中將分析如何通過domDiff(oldTree, newTree)的方法通過同樣的遍歷方法來收集變化並批量更新視圖。

4. 聲明

本篇只是部分原理的學習筆記,並不代表框架真實源碼的實現邏輯。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • XKZoomingView.h XKZoomingView.m USE ELSE ...
  • 使用jQuery增加或刪除元素(內容):一、jQuery添加元素或內容:1,append() 方法:在被選元素的結尾插入元素或內容 2,prepend() 方法:被選元素的開頭插入元素或內容。 3,after() 方法:在被選元素之後插入內容。 4,before() 方法:在被選元素之前插入內容。註 ...
  • 百度智能小程式自定義彈窗組件wcPop|百度小程式model對話框|智能小程式彈窗界面模板 最近百度也推出了自己的智能小程式,如是就趕緊去試了下,官方提供的api還不是狠完整。而且官方提供的彈窗組件也不能滿足一些複雜展示場景,所以就自己動手封裝了個智能小程式彈窗wcPop自定義模板插件。 百度智能小 ...
  • 支付寶小程式自定義彈窗組件wcPop|小程式自定義對話框|actionSheet彈窗模板 支付寶小程式官方提供的alert提示框、dialog對話框、model彈窗功能比較有限,有些都不能隨意自定義修改的。如是自己就捯飭著封裝了個支付寶小程式自定義彈窗插件wcPop,多種展示場景,隨意修改調用。 自 ...
  • With Custom Elements, web developers can create new HTML tags, beef-up existing HTML tags, or extend the components other developers have authored. ...
  • 1. 2. 3.(類似法2) ...
  • js如何判斷值是否是數字 1. isNaN()方法2. 正則表達式var re = /^[0-9]+.?[0-9]*$/; //判斷字元串是否為數字 //判斷正整數 /^[1-9]+[0-9]*]*$/3. 利用parseFloat的返回值 isNaN(inputData)不能判斷空串或一個空格;如 ...
  • 在掘金上看到了一位大佬發了一篇很詳細的面試記錄文章 "《一年半經驗,百度、有贊、阿裡面試總結》" ,為了查漏補缺,抽空就詳細做了下。( 估計只有我這麼無聊了哈哈哈 ) 有給出的或者有些不完善的答案,也儘力給出/完善了(可能有錯,大家自行辨別)。有些很困難的題目(例如實現 ),附帶相關鏈接(懶癌患者福 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...