Backbone前端框架解讀

来源:https://www.cnblogs.com/jingdongkeji/archive/2023/02/07/17098134.html
-Advertisement-
Play Games

作者: 京東零售 陳震 一、 什麼是Backbone 在前端的發展道路中,前端框架元老之一jQuery對繁瑣的DOM操作進行了封裝,提供了鏈式調用、各類選擇器,屏蔽了不同瀏覽器寫法的差異性,但是前端開發過程中依然存在作用域污染、代碼復用度低、冗餘度高、數據和事件綁定煩瑣等痛點。 5年後,Backbo ...


作者: 京東零售 陳震

一、 什麼是Backbone

在前端的發展道路中,前端框架元老之一jQuery對繁瑣的DOM操作進行了封裝,提供了鏈式調用、各類選擇器,屏蔽了不同瀏覽器寫法的差異性,但是前端開發過程中依然存在作用域污染、代碼復用度低、冗餘度高、數據和事件綁定煩瑣等痛點。

5年後,Backbone橫空出世,通過與Underscore、Require、Handlebar的整合,提供了一個輕量和友好的前端開發解決方案,其諸多設計思想對於後續的現代化前端框架發展起到了舉足輕重的作用,堪稱現代前端框架的基石。

通過對Backbone前端框架的學習,讓我們領略其獨特的設計思想。

二、 核心架構

按照MVC框架的定義,MVC是用來將應用程式分為三個主要邏輯組件的架構模式:模型,視圖和控制器。這些組件被用來處理一個面嚮應用的特定開發。 MVC是最常用的行業標準的Web開發框架,以創建可擴展的項目之一。 Backbone.js為複雜WEB應用程式提供模型(models)、集合(collections)、視圖(views)的結構。

◦ 其中模型用於綁定鍵值數據,並通過RESRful JSON介面連接到應用程式;

◦ 視圖用於UI界面渲染,可以聲明自定義事件,通過監聽模型和集合的變化執行相應的回調(如執行渲染)。

如圖所示,當用戶與視圖層產生交互時,控制層監聽變化,負責與數據層進行數據交互,觸發數據Change事件,從而通知視圖層重新渲染,以實現UI界面更新。更進一步,當數據層發生變化時,由Backbone提供了數據層和伺服器數據共用同步的能力。

其設計思想主要包含以下幾點:

◦數據綁定(依賴渲染模板引擎)、事件驅動(依賴Events)

◦視圖組件化,並且組件有了生命周期的概念

◦前端路由配置化,實現頁面局部刷新

這些創新的思想,在現代前端框架中進一步得到了繼承和發揚。

三、 部分源碼解析

Backbone極度輕量,編譯後僅有幾kb,貫穿其中的是大量的設計模式:工廠模式、觀察者模式、迭代器模式、適配器模式……,代碼流暢、實現過程比較優雅。按照功能拆分為了Events、Model、Collection、Router、History、View等若幹模塊,這裡摘取了部分精彩源碼進行瞭解析,相信對我們的日常代碼開發也有一定指導作用:

(1)迭代器

EventsApi起到一個迭代器分流的作用,對多個事件進行解析拆分,設計的非常經典,執行時以下用法都是合法的:

◦用法一:傳入一個名稱和回調函數的對象

modal.on({
    "change": change_callback,
    "remove": remove_callback
})

◦用法二:使用空格分割的多個事件名稱綁定到同一個回調函數上

model.on("change remove", common_callback)

實現如下:

var eventsApi = function(iteratee, events, name, callback, opts) {
    var i = 0, names;
    if(name && typeof name === 'object') {
        // 處理第一種用法
        if(callback !== void 0 && 'context' in opts && opts.context === void 0) opts.context = callback;
        for(names = _.keys(names); i < names.length; i++) events = eventsApi(iteratee, events, names[i], name[names[i]], opts);
    } else if(name && eventSplitter.test(name)) {
        // 處理第二種用法
        for(names = name.split(eventSplitter); i < names.length; i++) events = iteratee(events, names[i], callback, opts);
    } else {
        events = iteratee(events, name, callback, opts);
    }
    return events;
}

(2)監聽器

用於一個對象監聽另外一個對象的事件,例如,在A對象上監聽在B對象上發生的事件,並且執行A的回調函數:

A.listenTo(B, "b", callback)

實際上這個功能用B對象來監聽也可以實現:

B.on("b", callback, A)

這麼做的好處是,方便對A創建、銷毀邏輯的代碼聚合,並且對B的侵入程度較小。實現如下:

Events.listenTo = function(obj, name, callback) {
    if(!obj) return this;
    var id = obj._listenId || (obj._listenId = _.uniqueId('l'));
    // 當前對象的所有監聽對象
    var listeningTo = this._listeningTo || (this._listeningTo = {});
    var listening = listeningTo[id];
    
    if(!listening) {
        // 創建自身監聽id
        var thisId = this._listenId || (this._listenId = _.uniqueId('l'));
        listening = listeningTo[id] = {obj: obj, objId: id, id: thisId, listeningTo: listeningTo, count: 0};
    }
    // 執行對象綁定
    internalOn(obj, name, callback, this, listening);
    return this;
}

(3)Model值set

通過option-flags相容賦值、更新、刪除等操作,這麼做的好處是融合公共邏輯,簡化代碼邏輯和對外暴露api。實現如下:

set: function(key, val, options) {
    if(key == null) return this;
    // 支持兩種賦值方式: 對象或者 key\value
    var attrs;
    if(typeof key === 'object') {
        attrs = key;
        options = val;
    } else {
        (attrs = {})[key] = val;
    }
    options || (options = {});
    ……
    var unset = options.unset;
    var silent = options.silent;
    var changes = [];
    var changing = this._changing; // 處理嵌套set
    this._changing = true;
    
    if(!changing) {
        // 存儲變更前的狀態快照 
        this._previousAttributes = _.clone(this.attributes);
        this.changed = {};
    }
    var current = this.attributes;
    var changed = this.changed;
    var prev = this._previousAttributes;
    
    for(var attr in attrs) {
        val = attrs[attr];
        if(!_.isEqual(current[attr], val)) changes.push(attr);
        // changed只存儲本次變化的key
        if(!_.isEqual(prev[attr], val)) {
            changed[attr] = val;
        } else {
            delete changed[attr]
        }
        unset ? delete current[attr] : (current[attr] = val)
    }
    if(!silent) {
        if(changes.length) this._pending = options;
        for(var i=0; i<changes.length; i++) {
            // 觸發 change:attr 事件
            this.trigger('change:' + changes[i], this, current[changes[i]], options);
        }
    }
    if(changing) return this;
    if(!silent) {
        // 處理遞歸change場景
        while(this._pending) {
            options = this._pending;
            this._pending = false;
            this.trigger('change', this, options);
        }
    }
    this._pending = false;
    this._changing = false;
    return this;
}

四、 不足(對比react、vue)

對比現代前端框架,由於Backbone本身比較輕量,對一些內容細節處理不夠細膩,主要體現在:

◦視圖和數據的交互關係需要自己分類編寫邏輯,需要編寫較多的監聽器

◦監聽器數量較大,需要手動銷毀,維護成本較高

◦視圖樹的二次渲染僅能實現組件整體替換,並非增量更新,存在性能損失

◦路由切換需要自己處理頁面更新邏輯

五、為什麼選擇Backbone

看到這裡,你可能有些疑問,既然Backbone存在這些缺陷,那麼現在學習Backbone還有什麼意義呢?

首先,對於服務端開發人員,Backbone底層依賴underscore/lodash、jQuery/Zepto,目前依然有很多基於Jquery和Velocity的項目需要維護,會jQuery就會Backbone,學習成本低;通過Backbone能夠學慣用數據去驅動View更新,優化jQuery的寫法;Backbone面對對象編程,符合Java開發習慣。

其次,對於前端開發人員,能夠學習其模塊化封裝庫類函數,提升編程技藝。Backbone的組件化開發,和現代前端框架有很多共通之處,能夠深入理解其演化歷史。


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

-Advertisement-
Play Games
更多相關文章
  • (目錄) 概述 筆者在學習資料庫相關內容時,發現關於innoDB在RR級別下究竟能不能保證不發生幻讀這個問題,網上的資料眾說紛紜,筆者在經過總結和自己的試驗之後,在這裡結合自己的理解分析一下這個問題,若有謬誤,歡迎指正。筆者在這裡預設讀者都瞭解了關於幻讀以及innoDB中MVCC和鎖機制的情況,僅對 ...
  • ##一、 DataX為什麼要使用插件機制? 從設計之初,DataX就把異構數據源同步作為自身的使命,為了應對不同數據源的差異、同時提供一致的同步原語和擴展能力,DataX自然而然地採用了框架 + 插件 的模式: 插件只需關心數據的讀取或者寫入本身。 而同步的共性問題,比如:類型轉換、性能、統計,則交 ...
  • 本文從提升用戶行為分析效率角度出發,詳細介紹了H5埋點方案規劃,埋點數據採集流程,提供可借鑒的用戶行為數據採集方案;且完整呈現了針對頁面分析,留存分析的數倉模型規劃方案。 ...
  • 本文主要記錄對象存儲組件Minio、數據湖組件Hudi及查詢引擎Hive\Spark之間的相容性配置及測試情況,Spark及Hive無需多言,這裡簡單介紹下Minio及Hudi。 MinIO 是在 GNU Affero 通用公共許可證 v3.0 下發佈的高性能對象存儲。 它是與 Amazon S3 ...
  • Flutter是Google推出的一款UI工具包,可以通過一套代碼同時在iOS和Android上構建媲美原生體驗的精美應用。它使用Dart作為開發語言,不依賴原生控制項,而是將自有的控制項庫,通過Skia圖形引擎直接繪製在平臺所提供的畫布上。簡單來說,它擁有以下特性:不依賴平臺、組件庫原生實現、能高速渲... ...
  • Flex 佈局目前已經非常流行了,現在幾乎已經相容所有瀏覽器了。在文章開始之前我們需要思考一個問題:我們為什麼要使用 Flex 佈局? 其實答案很簡單,那就是 Flex 佈局好用。一個新事物的出現往往是因為舊事物不那麼好用了,比如,如果想讓你用傳統的 css 佈局來實現一個塊元素垂直水平居中你會怎麼 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 使用須知 2017年下半年,微信6.5.21版本支持線上音視頻功能。開發者可以通過兩個音視頻組件 和 實現實時地線上直播、視頻通話、語音通話等功能。 上述功能需要用到兩個小程式媒體組件中的兩個: live-pusher 與 live-pl ...
  • 摘要:當協議、子功能變數名稱、主功能變數名稱、埠號中任意一個不相同時,都算作不同域。不同域之間相互請求資源,就算作“跨域”。 本文分享自華為雲社區《九種跨域方式實現原理咋回事》,作者:龍哥手記 一、什麼是跨域? 1.什麼是同源策略及其限制內容? 同源策略是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...