日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一种SPA(单页面应用)架构

發布時間:2025/3/16 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一种SPA(单页面应用)架构 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

(如果對SPA概念不清楚的同學可以先自行了解相關概念)

? ? 平時喜歡做點小頁面來玩玩,并且一直采用單頁面應用(Single Page Application)的方式來進行開發。這種開發方式是在之前一年做的一個創業項目的經驗和思考,一直想寫篇博客來總結一下。

? ? 個人認為單頁面應用的優勢相當明顯:

  • 前后端職責分離,架構清晰:前端進行交互邏輯,后端負責數據處理。
  • 前后端單獨開發、單獨測試。
  • 良好的交互體驗,前端進行的是局部渲染。避免了不必要的跳轉和重復渲染。
  • ? ? 當然,SPA也有它自身的缺點,例如不利于搜索引擎優化等等,這些問題也有其相應的解決方案。

    ? ? 下面要介紹的這種方式可以說是一種模式或者工作流,和前端使用什么框架無關,也和后端使用什么語言、數據庫無關。不能說是The Best Practice,我相信經過更多人的討論和思考會有A Better Practice。:)

    概覽

    ? ? 下圖展示了這種模式的整個前后端及各自的主要組成:

    ? ? 看起來有點復雜,接下來會仔細地對上面每一個部分進行解釋。看完本文,就應該能理解上圖中的各部件之間的交互流程。

    前端架構

    ? ? 把上圖的前端部分單獨抽出來進行研究:

    ? ? 前端中大致分為四種類型的模塊:

  • components:前端UI組件
  • services:前端數據緩存和操作層
  • databus:封裝一系列Ajax操作,和后端進行數據交互的部件
  • common/utils:以上組件的共用部件,可復用的函數、數據等
  • components

    ? ? component指的是頁面上的一個可復用UI交互單元,例如一個博客的評論功能:

    ? ? 我們可以把博客評論做為一個組件,這個組件有自己的結構(html),外觀(css),交互邏輯(js),所以我們可以單獨做一個叫comment的 ? ? ? ?component,由以下文件組成:

  • comment.html
  • comment.css
  • comment.js
  • (每個component可以想象成一個工程,甚至可以有自己的README、測試等)

    components tree

    ? ? 一個component可以依賴另外一個component,這時候它們是父子關系;component之間也可以互相組合,它們就是兄弟關系。最后的結果就類似DOM tree,component可以組成components tree。

    例如,現在要給這個博客添加兩個功能:

  • 顯示評論回復。
  • 鼠標放到評論或者回復的用戶頭像上可以顯示用戶名片。
  • ? ? 我們構建兩個組件,reply和user-info-card。因為每個comment都要有自己的回復列表,所以comment組件是依賴于reply組件的,comment和reply組件是嵌套關系。

    ? ? 而user-info-card可以出現在comment或者reply當中,并且為了以后讓user-info-card復用性更強,它應該不屬于任何一個組件,它和其他組件是組合關系。所以我們就得到一個簡單的componenets tree:

    components之間的通信

    ? ? 怎么可以做到鼠標放到評論和回復的用戶頭像上顯示名片呢?這其實牽涉到組件之間是如何進行通信的問題。

    ? ? 最佳的方式就是使用事件機制,所有組件之間可以通過一個叫eventbus通用組件進行信息的交互。所以,要做到上述功能:

  • user-info-card可以在eventbus監聽一個user-info-card:show的事件。
  • 而當鼠標放到comment和reply組件的頭像上的時候,組件可以使用eventbus觸發user-info-card:show事件。
  • user-info-card:

    var eventbus = require("eventbus") eventbus.on("user-info-card:show", function(user) {// 顯示用戶名片 })

    comment or reply:

    var eventbus = require("eventbus") $avatar.on("mouseover", function(event) {eventbus.emit("user-info-card:show", userData) })

    ? ? components之間用事件進行通信的優勢在于:

  • 組件之間沒有強的依賴,組件之間被解耦。
  • 組件之間可以單獨開發、單獨測試。數據和事件都可以簡單的進行偽造進行測試(mocking)。
  • ? ? 總結:component之間有嵌套和組合的關系,構成components tree;component之間通過事件進行信息、數據的交換。

    services

    ? ? component的渲染和顯示依賴于數據(model)。例如上面的評論,就會有一個評論列表的model。

    comments: [{user:.., content:.., createTime: ..}, {user:.., content:.., createTime: ..}, {user:.., content:.., createTime: ..} ]

    ? ? 每個評論的component會對應一個comment(comments數組中的對象)進行渲染,渲染完以后就會正確地顯示在頁面上。

    ? ? 因為可能在其他component中也會需要用到這些數據,所以comment component不會自己直接保存這些comment model。這些model都會保存在service當中,而component會從service拿取數據。components和services之間是多對多的關系:一個component可能會從不同的services中拿取數據,而一個service可能為多個components提供數據。

    ? ? services除了用于緩存數據以外,還提供一系列對數據的一些操作接口。可以提供給components進行操作。這樣的好處在于保持了數據的一直性,假如你使用的是MVVM框架進行component的開發,對數據的操作還可以直接對多個視圖產生數據綁定,當services中的數據變化了,多個components的視圖也會相應地得到更新。

    ? ? 總結:services是對前端數據(也就是model)的緩存和操作。

    databus

    ? ? 而services中緩存的數據是從哪里來的呢?當然也許想到的第一個方案是在services中直接發送Ajax請求去服務器中拉去數據。而這里建議不直接這樣做,而是把各種和后端的API進行交互的接口封裝到一個叫databus的模塊當中,這里的databus相當于是“對后端數據進行原子操作的集合”。

    ? ? 如上面的comment service需要從后端進行拉取數據,它會這樣做:

    var databus = require("databus") var comments = null databus.getAllComments(function(cmts) { // 調用databus方法進行數據拉取comments = cmts })

    ? ? 而databus中則封裝了一層Ajax

    databus.getAllCommetns = function(callback) {utils.ajax({url: "/comments",method: "GET",success: callback}) }

    ? ? 這樣做是因為,不同的services之間可能會用到同樣的接口對后端進行操作,把操作封裝起來可以提高接口的復用性。注意,如果databus中的某些操作不涉及到servcies的數據,這操作也可以被components所調用(例如退出、登錄等)。

    ? ? 總結:databus封裝了提供給services和component和后端API進行交互的接口。

    common/utils

    ? ? 這兩個模塊都可以被其他組件所依賴。

    ? ? common,故名思議,組件之間的共用數據和一些程序參數可以緩存在這里。

    ? ? utils,封裝了一些可復用的函數,例如ajax等。

    eventbus

    ? ? 所有組件(特別是components之間)的通過事件機制進行數據、消息通信的接口。可以簡單地使用EventEmitter這個庫來實現。

    后端架構

    ? ? 傳統的網頁頁面一般都是由后端進行頁面的渲染,而在我們的架構當中,后端只渲染一個頁面,其后,后端只是相當于一個Web Service,前端使用Ajax調用其接口進行數據的調取和操作,使用數據進行頁面的渲染。

    ? ? 這樣的好處就是,后端不僅僅能處理Web端的頁面的請求,而且處理提供移動端、桌面端的請求或者作為第三方開放接口來使用。大大提高后端處理請求的靈活性。

    ? ? 后端對比起前端的架構來說會簡單很多,但是這只是其中一種模式,對于不同復雜程度的應用可能會做相應的調整。后端大概分為三層:

  • CGI:設置不同的路由規則,接受前端來的請求,處理數據,返回結果。
  • business:這一層封裝了對數據庫的一些操作,business可以被CGI所調用。
  • database:數據庫,進行數據的持久化。
  • ? ? 例如上面的comments的例子,CGI可以接收到前端發送的請求:

    var commentsBusiness = require("./businesses/comments") app.get("/comments", function(req, res) {// 此處調用comments的business數據庫操作commentsBusiness.getAllComments(function(comments) {// 返回數據結果res.json(comments)}) })

    ? ? 后端的API可以采用更規范的RESTful API的方式,而RESTful不在本文的討論范圍內。有興趣的可以參考Best Practices for Designing a Pragmatic RESTful API。

    ? ? 前后端的架構都基本清晰了,我們來看看文章開頭的圖:

    ? ? 看著圖來,我們總結一下整個前后端的交互流程:

  • 前端向服務端請求第一個頁面,后端渲染返回。
  • 前端加載各個component,components從services拿數據,services通過databus發送Ajax請求向后端取數據。
  • 后端的CGI接收到前端databus發送過來的請求,處理數據,調用business操作數據庫,返回結果。
  • 前端接收到后端返回的結果,把數據緩存到service,component拿到數據進行前端組件的渲染、顯示。
  • 工作流

    ? ? 一個好的工作流可以讓開發事半功倍。上面的這種單頁面應用也有其相應的一種開發工作流,當然這種工作流也適合非單頁面應用:

  • 進行產品功能、原型設計。
  • 后端數據庫設計。
  • 根據產品確定前后端的API(or RESTful API),以文檔方式紀錄。
  • 前后端就可以針對API文檔同時進行開發。
  • 前后端最后進行連接測試。
  • ? ? 前后端分離開發。建議都可以采用TDD(測試驅動開發)的方式來單獨測試、單獨開發(關于Web APP測試這一塊可以單獨進行討論研究),提高產品的可靠性、穩定性。

    (完)

    總結

    以上是生活随笔為你收集整理的一种SPA(单页面应用)架构的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。