前端技術演進(七):前端跨棧技術

這個來自以前作的培訓,刪減了一些業務相關的,參考了不少資料( 參考資料列表),謝謝前輩們,麼麼噠 😘

隨着互聯網架構的不斷演進,前端技術框架從後臺輸出頁面到後臺MVC,再到前端MVC、MVP、MVVM,以及到Virtual DOM和MNV*的實現,已經發生了巨大的變化。總體上來看,前端也正在朝着模塊化、組件化和高性能Web開發模式化的方向快速發展。除了傳統桌面瀏覽器端Web上的應用,前端技術棧在服務端或移動端上的嘗試和發展也歷來沒有中止過,並且造成了一系列成熟的解決方案。前端的技術棧能解決的不僅是頁面上的問題,前端工程師的追求也毫不只是頁面上的技術。html

跨後端技術

這幾年全棧工程師已成爲一個很熱門的關鍵詞,從最先的MEAN技術棧到後端直出,再到如今的先後端同構,前端經過與Node結合的開發模式愈來愈被開發者認同並在愈來愈多的項目中獲得實踐。前端開發者都熱衷於在Node上開發有如下幾個緣由:前端

  • Node是一個基於事件驅動和無阻塞的服務器,很是適合處理併發請求,所以構建在Node上的應用服務相比其餘技術實現的服務性能表現要好。
  • Node端運行的是JavaScript,對於前端開發者來講學習成本較低,要關注的問題相對來講比前端更純粹些。
  • 做爲一名前端工程師確實須要掌握一門後臺語言來輔助本身的技術學習。
  • Node端處理數據渲染的方式可以解決前端沒法解決的問題,這在大型Web應用場景下的優點就體現出來了,這也是目前Node後端直出或同構的實現方式被開發者普遍使用的一個重要緣由。

Node後端開發

Node.js 是一個基於 Chrome V8 引擎 的 JavaScript 運行時。react

有個叫Ryan Dahl的歪果仁,他的工做是用C/C寫高性能Web服務。對於高性能,異步IO、事件驅動是基本原則,可是用C/C寫就太痛苦了。因而這位仁兄開始設想用高級語言開發Web服務。他評估了不少種高級語言,發現不少語言雖然同時提供了同步IO和異步IO,可是開發人員一旦用了同步IO,他們就再也懶得寫異步IO了,因此,最終,Ryan瞄向了JavaScript。在2009年,Ryan正式推出了基於JavaScript語言和V8引擎的開源Web服務器項目,命名爲Node.js。web

Node第一次把JavaScript帶入到後端服務器開發,加上世界上已經有無數的JavaScript開發人員,因此Node一會兒就火了起來。Node最大的優點是藉助JavaScript天生的事件驅動機制加V8高性能引擎,使編寫高性能Web服務垂手可得。sql

阻塞和非阻塞

阻塞 是說 Node.js 中其它的 JavaScript 命令必須等到一個非 JavaScript 操做完成以後才能夠執行。這是由於當 阻塞 發生時,事件機制沒法繼續運行JavaScript。數據庫

在 Node.js 中,JavaScript因爲 CPU 密集操做而表現不佳。而不是等待非 JavaScript操做 (例如I/O)。這被稱爲 阻塞編程

阻塞 方法執行起來是 同步地 ,可是 非阻塞 方法執行起來是 異步地 。 使用文件系統模塊讀取一個文件,同步方法看上去以下:後端

const fs = require('fs');
const data = fs.readFileSync('/file.md'); // 這裏會阻塞複製代碼

與之功能等同的 異步 版本:react-native

const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
  if (err) throw err;
});複製代碼

在第二個例子中, fs.readFile() 由於是 非阻塞 的,因此 JavaScript 會繼續執行,不會發生阻塞, 這對於高效吞吐來講是絕佳的設計。瀏覽器

在 Node.js 中 JavaScript 的執行是單線程的,因此並行與事件輪詢能力(即在完成其它任務以後處理 JavaScript 回調函數的能力)有關。任何一個企圖以並行的方式運行的代碼必須讓事件輪詢機制以非 JavaScript 操做來運行,像 I/O 操做。

好比 每一個對服務器的請求消耗 50 毫秒完成,其中的 45 毫秒又是能夠經過異步操做而完成的數據庫操做。選擇 非阻塞 操做能夠釋放那 45 毫秒用以處理其它的請求操做。這是在選擇 阻塞非阻塞 方法上的重大區別。

Node.js 中的事件輪詢機制和其它語言相比而言有區別,其它語言通常須要建立線程來處理並行任務。

MEAN

Node出現的早期還不像如今同樣擁有很複雜的概念,相關技術和語言的標準還不成熟,Node開發通常用的比較多的方案就是使用Express做爲Web框架進行小型的Web站點建設,與之結合的主流技術則以M(Mysql)、E(Express)、 A(Angular)、 N(Node)最爲典型,甚至到了今天MEAN技術組合的方式仍在沿用。

image.png | center | 712x530

前端通常使用Angular來管理實現頁面應用,服務端Web框架以Express爲主,同時使用免費開源的MongoDB數據庫,這樣就能夠很快地構建一個Web應用了。

今天可能不必定再去選擇使用它,由於能夠代替實現的成熟方案已經不少了,各種其餘先後端框架均可以用來靈活組合做爲MEAN的替代選型方案,好比 Vue、React能夠替代 Angular,Koa 能夠替代 Express,數據庫的選擇也有不少。

Node後端數據渲染

對於前端開發者來講,在大型Web應用開發中,不少時候並不須要徹底從新設計整個應用後臺的架構,更多的狀況下須要結合Node的能力幫助咱們解決先後端分離開發模式下沒法解決的問題。咱們先來看下一般先後端分離的開發模式下有哪些問題,利用Node 端的服務又是如何幫助咱們解決這些問題的:

SPA場景下SEO的問題

一般狀況下,SPA應用或先後端分離的開發模式下頁面加載的基本流程是:

  1. 瀏覽器端先加載一個空頁面和JavaScript 腳本。
  2. 而後異步請求接口獲取數據。
  3. 渲染頁面數據內容後展現給用戶。

那麼問題來了,搜索引擎抓取頁面解析該頁面HTML中關鍵字、描述或其餘內容時,JavaScript還沒有調用執行,搜索引擎獲取到的僅僅是一個空頁面,因此沒法獲取頁面上<body>中的具體內容,這就比較影響搜索引擎收錄頁面的內容排行了。儘管咱們會在空頁面的<meta>裏面添加keyword和description的內容,但這確定是不夠的,由於頁面關鍵性的正文內容描述並無被搜索引擎獲取到。

若是使用Node後端數據渲染(有人稱之爲直出或服務端渲染 SSR),在頁面請求時將內容渲染到頁面上輸出,那麼搜索引擎獲取到的HTML就已經包含頁面完整的內容,頁面也就更容易被檢索到了。

前端頁面渲染展現緩慢的問題

除了SEO問題,在先後端分離的開發模式下頁面在JavaScript執行渲染以前是空白的(或提示用戶加載中)。用戶在看到數據時已經花費的網絡等待時間包括:

DOM下載時間 + DOM解析時間 + JavaScript 文件請求時間 + JavaScript部分執行時間 + 接口請求時間 + DOM渲染時間。

這時用戶看到頁面數據時已是三次串行網絡資源請求以後的事情了。若是使用後端直出來進行數據渲染,首先SEO的問題不復存在,用戶瀏覽器加載完DOM的內容解析後便可當即展現,網絡加載的問題也獲得解決。其餘的邏輯操做(如事件綁定和滾動加載的內容)則可按需、按異步加載,從而大幅度減小展現頁面內容花費的時間。

通常後臺頁面數據直出的通用架構設計以下:

image.png | center | 600x446

直出層接受前端的路由請求,並在Node端的Controller層異步請求服務接入層接口,得到Model數據並進行組裝拼接,而後提取相對應的Node端View模板渲染出HTML輸出給用戶瀏覽器,而不用經過前端JavaScript請求動態數據後渲染。

不只如此,直出層根據不一樣的瀏覽器userAgent,也能夠提取不一樣的模板渲染頁面返回給不一樣的用戶瀏覽器,因此這種實現方式不只很是適合大型應用服務的實現場景,並且能夠方便地實現網站的響應式內容直出。

先後端同構

在先後端分離的開發模式上加入直出層,解決了SEO和數據加載顯示緩慢的問題。但是有兩個新的問題:

  • 前端的開發實現向直出層偏移,不得不在原來的開發模式上作出修改來 適應直出層內容的開發,例如修改後端模板來適應現有的開發模式,結果咱們不得不維護兩套不一樣的先後臺模板或技術實現——前端渲染實現邏輯和後端直出實現邏輯,儘管可能都是用JavaScript寫的。
  • 若是是在移動端Hybrid應用上,離線包機制實現可能就會出現問題。由於每次都是從後端直出HTML結構給前端,這樣就難作到將HTML文件進行離線緩存,而只能進行其餘靜態文件的緩存。在Hybrid App的應用場景下,其實咱們更但願作到的是移動端首次打開頁面時使用後端直出內容來解決加載慢和SEO問題,而在有離線緩存的狀況下則使用客戶端本地緩存的靜態文件拉取數據返回渲染的方式來實現,或者將來在高版本的瀏覽器支持HTTP2的條件下使用前端渲染,低端瀏覽器不支持HTTP2的狀況下則使用直出的方式實現。

因此須要一套完善的開發方式,和原有開發方式保持一致,且可以同時用於先後端分離的開發模式和後端數據渲染模板開發方式中。這種開發模式就是咱們所說的先後端同構。

實現同構的核心

先後端同構的宗旨是,只開發一套項目代碼,既能夠用來實現前端的JavaScript 加載渲染,也能夠用於後臺的直出渲染。

爲何能夠這樣作呢?和前端渲染數據內容的方式相同,頁面直出層內容也是經過數據加上模板編譯的方式生成的,前端渲染和後臺直出的模式生成DOM結構的區別只在於 數據和模板的渲染髮生在何時。若是使用一套能在前端和後端都編譯數據的模板系統,就能夠作到使用同一套開發代碼在先後端分別進行數據渲染解析。所以先後端同構的核心問題是實現先後臺數據渲染的統一性。

同構的優點

除了解決先後端開發方式的問題,先後端同構的網站具備一些明顯的優點:

  • 能夠根據用戶的需求方便地選擇使用前端渲染數據仍是後臺直出頁面數據;
  • 開發者只需維護一套前端代碼,並且能夠沿用前端原有的項目組件化管理、打包構建方式,根據不一樣的構建指令生成相似的先後端數據模板或組件在先後端執行解析,因此這對於DOM結構層上的開發方式應該是一致的。

先後端同構的實現原理

基於數據模板的先後端同構方案

早在前端MVC開發的時代,前端模板的使用就很是普遍,例如Mustache、Handlebar 等,基本原理是將模板描述語法與數據進行拼接生成HTML代碼字符串插入到頁面特定的元素中來完成數據的渲染。同理,後端直出層也能夠經過該方法來實現數據的渲染產生HTML字符串輸出到頁面上。

若是先後端使用同一個模板解析引擎,那麼咱們只須要編寫同一段模板描述語法結構就能夠在前端和後端分開進行渲染了。好比一樣的模板:

<div class="entry">
  <h1>{{title}}</h1>
  <div class="body">
    {{body}}
  </div>
</div>複製代碼

前端,後端拿到數據後解析保持一致:

{
  "title": "Hello",
  "body": "World"
}複製代碼
<div class="entry">
  <h1>Hello</h1>
  <div class="body">
    World
  </div>
</div>複製代碼

對於前端開發的同一段模板語法結構,咱們既能夠選擇在瀏覽器端渲染生成HTML字符串輸出,也能夠選擇在後端渲染生成HTML字符串輸出。若是選擇在前端渲染,則能夠將模板進行打包編譯,在數據請求成功後進行DOM渲染;若是選擇後端渲染,就能夠將模板數據直接發送到直出層的View視圖進行渲染,實現同一個模板語法結構在先後端渲染出相同的內容。這裏的前提是要保證先後端使用的模板渲染引擎或者模板解析的語法是一致的。

基於MVVM的先後端同構

MVVM框架頁面上的JavaScript邏輯主要是經過Directive(不僅是Directive,還有filter、 表達式等,以Directive爲主)來實現的,通常前端頁面加載完成後會開始掃描DOM結構中的Directive指令並進行DOM操做渲染或事件綁定,因此數據的顯示仍然須要頁面執行Directive後才能完成。那麼若是將Directive的操做在直出層實現,瀏覽器直接輸出的頁面就是渲染後的內容數據了。

<div class="entry">
  <h1 x-html="title"></h1>
  <div class="body" x-html="body"></div>
</div>複製代碼

前端編寫的同一段MVVM的語法結構,經過前端MVVM框架解析或後端Directive 運行解析最終均可以生成相同的HTML結構,不一樣的是前端執行解析後生成的是ViewModel對象並經過瀏覽器體現,後端渲染則生成HTML標籤的文本字符串輸出給瀏覽器。這裏一樣須要作一件事,即在後臺實現一個與前端解析Directive相同的模塊,甚至還包括filter、語法表達式等的實現。這樣就能夠在先後端完成同一段語法結構的解析了。

基於VirtualDOM的先後端同構

以前說過,VirtualDOM做爲一種新的編程概念被普遍應用在實際項目開發中,其核心是使用JavaScript 對象來描述DOM結構。那麼既然Virtual DOM是一個JavaScript對象,就表示其能夠同時存在於先後端,經過不一樣的處理方式來實現同構。

在前端開發的組件中聲明某段VirtualDOM描述語法,而後經過VirtualDOM框架解析生成VirtualDOM,這裏的VirtualDOM既能夠用於在瀏覽器端生成前端的DOM結構,也能夠在直出層直接轉換成HTML標記的文本字符串輸出,後面這種狀況就能夠在服務端上實現Virtual DOM到HTML文本字符串的轉換。這樣,經過對Virtual DOM的不一樣操做處理,就能夠統一先後端渲染機制,實現組件的先後端對同一段描述語法進行渲染。

這裏VirtualDOM上的邏輯實現仍然須要在瀏覽器端進行事件綁定來完成,最好能讓同構框架幫助咱們自動完成,根據HTML的結構進行特定的事件綁定處理,保證最後展現給用戶的頁面是完整且帶有交互邏輯的

不管哪種方式,核心都體如今HTML的結構形式變化上,頁面內容的描述方式有不少,並且能夠經過特定的處理過程實現轉化,這樣就提供了更多的可能性。

image.png | center | 390x370

Egg.js

image.png | center | 89x28

Node雖然生態比較火熱,可是至今尚未一款公認的成熟的企業級框架,主要是由於使用Node來開發大型後端應用的企業還不多。如今主要有兩款:Sails 和 Egg.js。

設計原則

一個插件只作一件事:Egg 沒有內置不少額外的功能,而是經過插件的方式來實現,Egg 經過框架聚合這些插件,並根據本身的業務場景定製配置,這樣應用的開發成本就變得很低。

約定優於配置:按照一套統一的約定進行應用開發,團隊內部採用這種方式能夠減小開發人員的學習成本,這也是不少框架的思路。

特色

  • 提供基於 Egg 定製上層框架的能力:能夠基於 Egg 去封裝適合團隊的上層框架。
  • 高度可擴展的插件機制:能夠促進業務邏輯的複用,生態圈的造成。
  • 內置多進程管理。
  • 基於 Koa 開發,性能優異:支持全部的Koa中間件。
  • 框架穩定,測試覆蓋率高。
  • 漸進式開發:能夠流暢的實現編碼 --> 編碼抽象成功能 --> 功能抽象成插件 --> 插件封裝到框架 的漸進過程。

eggjs.org/zh-cn

如今咱們部門的Node項目基本上是 Koa,Egg流。其餘部門也有 Express 流。

跨終端技術

移動端

移動互聯網興起後,智能移動設備出現,大量應用市場的Native應用也開始涌現。隨着第一波移動端互聯網開發浪潮漸漸平靜,各種Native應用開始進入有序更新迭代的階段。人們對移動互聯網需求急劇增加,Native 應用快速迭代開發的需求也愈來愈多,可是現有Native應用的開發迭代速度依然沒法知足市場快速變化的須要。隨之而來的是HTML5的出現,它容許開發者在移動設備上快速開發網頁端應用,並讓移動互聯網應用開發很快進入了Native應用、Web應用、Hybrid 應用並存的時代。

image.png | center | 600x305

在發展過程當中,最大限度的利用原生能力成爲了一大趨勢。出現了 React Native、Weex 等框架,能夠直接使用 Javascript 來編寫原生應用。好比React Native,產出的並非「網頁應用」, 或者說「HTML5應用」,又或者「混合應用」。 最終產品是一個真正的移動應用,從使用感覺上和用Objective-C或Java編寫的應用相比幾乎是沒法區分的。

import React, { Component } from 'react';
import { Text, View } from 'react-native';

class WhyReactNativeIsSoGreat extends Component {
  render() {
    return (
      <View>
        <Text>
          若是你喜歡在Web上使用React,那你也確定會喜歡React Native.
        </Text>
        <Text>
          基本上就是用原生組件好比'View''Text'
          來代替web組件'div''span'。
        </Text>
      </View>
    );
  }
}複製代碼

image.png | center | 618x544

也就是說即便不懂原生應用的開發,也能夠用 Javascript 來編寫原生應用了。

桌面端

如今,也可使用 JavaScript, HTML 和 CSS 構建跨平臺的桌面應用。經過 Electron 之類的應用,能夠直接把 Web 項目打包成桌面應用,運行在各個操做系統中。

著名的 Atom IDE 就是經過 Electron 構建的,其餘的包括 VS Code、Skype、Github Desktop 之類的 App 也都是經過 Electron 構建的。

image.png | center | 718x902

相關文章
相關標籤/搜索