1. 程式人生 > >2017年Web前端技術綜述

2017年Web前端技術綜述

Web前端應用發展的歷史大概經歷了三個階段:第一個階段使用的是簡單的靜態頁面,第二個階段使用得是ASP、JSP、PHP等動態指令碼語言,第三個階段是Web2.0階段,其核心技術是AJAX,同時伴隨著SPA的興起。

SPA vs. MPA

從字面上理解,SPA(單頁面應用程式)整個應用只有一個頁面,只加載一次Web靜態資源,包括HTML+CSS+javascript,在導航過程中不需要重新載入渲染整個頁面。而MPA恰恰相反,也就是每個頁面都需要獨立完整的從後端載入和渲染,早期的網站大多屬於MPA。


那麼SPA和MPA各自有哪些優缺點呢?

SPA第一次載入頁面因為要載入很多靜態資源,速度比較慢,但是之後前後端僅僅需要傳遞純資料,頁面渲染完全由前端完成,既節省了頻寬,也提高了渲染速度。MPA則反之,使用者的每次導航、提交表單都需要由後端生成一個完整的頁面,前後端之間傳遞了大量重複類似的標記語言文字,通訊效率較低。但是由於在首頁載入速度上,MPA相對有優勢,所以有些應用出於使用者體驗的考慮,結合server side render和SPA的混合方式。
從系統架構角度考慮,SPA最重要的革新在於實現了前後端的解耦,Server端不必既要考慮業務邏輯又要考慮頁面展示,只要聚焦於業務,將前端需要的資料開放出來即可。後端聚焦於資料之後,可以被多種前端所共享,比如Web應用,Mobile應用,甚至是AR/VR等,即所謂的大前端。對於Web前端,因為靜態資源都已經載入,導航、渲染等介面邏輯都放在瀏覽器端,所以可以使用如chrome developer tool或者firebug等工具獨立除錯。NodeJS的出現,甚至讓Web應用開發和業務開發從語言層面進行了完全解耦。
SPA和MPA各有優劣,雖說SPA面臨SEO困難,易受XSS攻擊等問題,但總體上說,優點多於缺點,問題正在解決,SPA已經成為Web 2.0時代的主流方式。

三駕馬車


Web應用萬變不離其宗,位於Web技術核心地位的仍舊是HTML、CSS、JavaScript三駕馬車。

HTML5提供了更豐富的語義化標籤、富媒體支援、離線儲存、移動裝置支援等特性,支撐了不斷湧現的各種業務需求,比如視訊網站、網頁遊戲等。CSS3提供了更加豐富且實用的規範,各種特效、變換等效果增強了網頁的表現能力,媒體查詢方便了網頁適配多種終端。網際網路時代,各種應用層出不窮,僅僅依靠HTML和CSS無法滿足使用者對網頁互動和表現能力的需求,JavaScript成為瀏覽器端最主要的程式語言。

伴隨著Web前端業務越來越複雜,開發、除錯愈加困難,前端技術在開發維護效率、擴充套件性、健壯性等內外需求的驅動下出現了各種各樣的技術。根據GitHub網站的統計,2017年Javascript相關的pull requests遙遙領先於其他語言,比第二名的Python和第三名的Java的總和還多。人說2017年最火爆的是AI,AI帶來Python的空前繁榮,但即便如此又奈我何?

當初,JavaScript之父Brendan Eich借鑑了C語言的語法、Java的記憶體管理、Scheme語言的函數語言程式設計以及Self的原型鏈繼承思想,僅僅花了10天就設計出這門語言,但倉促的設計導致各種問題飽受詬病,於是有人說JavaScript是一門天生殘疾的語言。自1995年誕生之後JavaScript一直緩慢發展,目前最廣泛支援的版本是2009年釋出的ES5版本,經過了多年的潛心打磨,TC39作為JavaScript官方機構,終於於2015年釋出了ES6。ES6做出了很多實質性的升級,比如塊變數、class、native promise、模組化等。最近幾年,Javascript的版本釋出逐漸年度例行化,2016年釋出了ES7,2017年釋出了ES8,JavaScript正向著標準、高效、簡潔、健壯的方向邁進。

前端技術棧

框架是什麼?模式是什麼?都是不得已而為之的事情。當家裡的桌子上堆滿了爆米花、手機、內衣、蟑螂藥和洗手液的時候,似乎這時候我們應該發明出抽屜,把東西分門別類地歸置一下。當用JavaScript手忙腳亂直接操作DOM的時候,JQuery誕生了;當前端程式碼變得複雜而有章可循時,新框架誕生了;當各種框架、庫讓人眼花繚亂,無所適從時,包管理、包載入被髮明出來;當button、panel、chart做得越來越漂亮時,新的控制元件庫產生了;當bug滿地走,除錯已經忙不過來的時候,測試框架出現了。框架和類庫就是幫我們把一些重複的並且已經受過驗證的模式,抽象到一個幫你設計好的封裝當中,幫助我們去應對這些複雜的問題。
前端生態是如此昌盛,以致於“前端年年框架出,各領風騷兩三年”,沒有選擇是痛苦的,選擇太多也痛苦,最痛苦的是用了一個以後卻很快出來另一個更酷的!沒有一篇文章能夠囊括整個前端生態,只能基於主要業務場景,基於主流方案,有選擇地做一些介紹和分析,即便這樣,也難免掛一漏萬。

下面,將前端技術分解為不同角度和層次來介紹。
* 前端語言
* JS工具庫
* 前端MVC框架
* UI框架
* 模組化和打包
* 自動化構建
* 包管理
* 測試工具
* 前後端協議

1. 前端語言

從ES6開始,JavaScript語言本身的標準化和發展進入新階段。除了一些語法糖,如胖箭頭、includes方法、class關鍵字等,讓JS程式碼更加清爽外,新的extend繼承方式、塊變數等特性的引入則讓JS更加像一門“正常”的語言。
非同步操作似乎是JavaScript規範一直在孜孜解決的問題,從最早的回撥函式,到Promise,到Generator函式,再到async,這些新特性一方面解決了回撥地獄問題,另外一方面也讓程式碼更加符合人類的序列思維方式。如果覺得Promise這種非同步處理方式滿足不了複雜的應用場景,可以考慮一下RxJS。引用官網的說法:RxJS是使用Observables的響應式程式設計的庫,它使編寫非同步或基於回撥的程式碼更容易。
儘管有些瀏覽器不支援ES5以後的JavaScript新特性,但有Babel在,儘管放手使用最新的ES特性。將Babel串到你的構建流程中,它會將新的特性轉化為瀏覽器支援更好的ES5程式碼。
JavaScript的弱型別經常會導致一些bug,這時候可以使用Flow/JSHint等靜態檢查工具。為提高程式碼可讀性,可以使用Prettier來美化程式碼。
TC39的長期不作為,讓一批不甘被ES5束縛住手腳的“方言”湧現出來,或者叫flavor,如CoffeeScript、Dart、Elm、TypeScript、Reason等。這些語言的初衷或者是為彌補原生JavaScript語言特性的不足,將一些更高階的語法引入進來,或者直接採用一種更成熟的語法,然後編譯為JavaScript。從目前發展來看,CoffeeScript、Dart已經衰落,而TypeScript、Reason正當紅,這些語言中一些有價值的特性逐漸被ECMAScript納入標準,但是是否會取代JavaScript或者多大程度上取代JavaScript還很難說。
上面的各種方言不管如何強大,最後還是要transpile到JavaScript,JS在瀏覽器端一路高歌猛進,獨孤求敗,似乎千秋大業已成。但在某個角落,一股反叛力量正在孕育,這就是由谷歌,微軟,Mozilla,蘋果等公司合作推出的WebAssembly!看看有多反動:“一種全新的跨瀏覽器Web中間表示層安全程式碼,為未來瀏覽器帶來一種可執行的標準二進位制資料格式,使得越來越多的開發者,不僅僅是JavaScript開發者,甚至是Rust,C#,Go語言的開發者,藉助統一的編譯機制,預先將這些語言開發的邏輯編譯為瀏覽器可以執行的二進位制程式碼格式,以此提高Web內容的效能和表現能力,同時為更多語言的開發者提供一種為Web開發內容的有效途徑。” 注意,WebAssembly是可以在瀏覽器上直接執行的唯二語言。2017年,Chrome,Firefox,IE,Safari四個瀏覽器統一通過了WebAssembly的方案。如果說nodejs的出現讓JavaScript的開發者能夠染指後臺開發的話,那麼WebAssembly似乎要革了JavaScript的命,動搖了其在瀏覽器上的霸主地位,很多語言都能直接開發Web應用了。

2. JS工具庫和基礎庫

Underscore和Lodash是非常優秀的JavaScript工具庫,提供了非常多的工具方法用於操作集合、陣列、方法、物件等。但是,當我們現在進行開發時,很多時候我們利用的方法已經被ES5與ES6所支援了,如果希望減少依賴的話,可以根據目標瀏覽器來選擇不用Lodash或者Underscore。
jQuery曾被譽為Web開發的瑞士軍刀,是前端程式設計師的必備技能,解決了瀏覽器的相容性問題,但是對DOM的隨意操作會導致程式難以維護。隨著各種現代框架的出現,jQuery的風頭似乎正被掩蓋,在google趨勢上從2012年達到最高點後一路走低。不可否認的是,目前以及未來一段時間內,大多數Web應用仍然會依賴jQuery及其相關外掛。
其它,跟Underscore和Lodash類似的還有Ramda,跟jQuery類似的有Prototype和Zepto。
為防止資料被無意更改而導致很隱晦的bug,可以考慮用Immutable.js,它可以將資料封裝確保狀態不被改變。

3. 前端MVC框架

通常前端技術選型最核心的決策點就是所謂的前端MVC框架,網上充斥著這類框架的對比文章,但是孰優孰劣仍然是蘿蔔白菜,各有所愛,說一句正確的廢話就是:框架的選擇要因地制宜,根據應用場景和團隊實際情況來定。

目前熱度最高的三大前端框架是Angular(2.0+)、React和Vue.js。三者都採用了元件化的思想,同一component的html、js、css組織在一起,元件化思想對早期絕對的“關注點分離”則檔案分離思想是一定程度的矯正,利於元件的單獨開發和複用,減輕了html、js,特別是css的全域性汙染問題。
Angular是由Google推出的基於TypeScript的MVVM框架,檢視和模型雙向繫結,通過指令增強模板的表達能力,同時可以自定義元件化的指令,支援依賴注入、註解。由於策略上的問題,Angular2.0不相容AngularJS 1.0,因此,近兩年Angular的活躍度有所下降,然而其內建完備的特性和工具讓擁護者們認為它是一個企業級的JS框架。
React由Facebook主推,最顯著的特點是一切以JS為中心,HTML和CSS都由JS程式碼生成,為此,還產生了一種新的語法:JSX,這跟Angular把JS以擴充套件標籤的形式放到HTML中是完全相反的做法。React實現了Virtual DOM,在DOM頻繁變化的場景下,效能有不錯的表現。另外,React本身主要關注於檢視層,並不是一個大而全的框架,由於React認為MVC架構在大規模應用場景下會導致狀態的混亂,因此創新地提出了單向資料流(Unidirectional data flow)的概念,出現了狀態管理的模式或框架,如Flux/Redux。
Vue.js是三者之中最年輕、最輕量的一個框架,由華裔程式設計師尤雨溪發起,也是主要關注檢視部分,既支援雙向繫結也可以單向繫結。Vue.js的模板語法有點類似於Angular,提供了一些內建標籤。Vue.js支援單檔案元件,也就是將html、js、css寫到一個字尾為.vue的檔案中,也支援Virtual DOM,效能表現在三者中最好。Vue.js可以使用Redux做狀態管理,但也提供了自己的Vuex。
值得一提的是,上面三個主流框架都有對應的移動端方案,比如Angular對應的Ionic,React的React Native以及Vue對應的Weex(阿里開發)。
資料和檢視的不同互動方式催生出幾個不同的概念:MVC、MVP、MVVM以及單向資料流。
下圖是2017年不同國家對幾大框架使用情況的調查反饋。

4. UI框架

上一節提到過React和Vue.js都專注於MVC的View,那它們跟UI框架什麼區別呢?上一節說的View只關心DOM物件的生成及互動響應,而這一節裡面的框架、庫則真正決定UI長什麼樣、是否美觀。這裡繼續細分的話又可以分為CSS框架(包括前處理器)、UI控制元件庫、資料視覺化庫等等。
所謂CSS框架其實也就是提前寫好的一些CSS,只要在你的HTML中加上對應的類,就能展現出CSS應用的效果。CSS框架雖然也很多,但是影響力比較大的仍舊是老牌的Bootstrap、Foundation、Semantic-ui等,可能由於一些公司有內部UI規範或者CSS還沒複雜到需要框架的原因,在stateofjs調查中,很多人不用CSS框架。從CSS發展的趨勢看,移動優先,響應式佈局,支援網格佈局和Flexbox技術,這些是最新CSS框架著力發展的方向。
CSS預處理工具的主要目的是彌補CSS語法不夠強大,解決書寫囉嗦,維護困難等問題。目前最主流的三個前處理器是SASS/SCSS、LESS和Stylus,主要特性是提供了變數、函式和mixin、import以及一些邏輯控制語法等。不同於SASS等工具, PostCSS通過強大的外掛體系,可以對CSS進行各種不同的轉換和處理,包括語法檢查 stylelint 外掛、交叉編譯sugarss 外掛)、命名改編以避免選擇器衝突( modules 外掛 )、模板 CSS 程式碼生成( autoprefixer 外掛 )、檔案壓縮等等。
CSS-in-JS是一種用JavaScript編寫CSS樣式的技術,通過鼓勵採用一種通用模式,編寫樣式以及應用樣式的JavaScript元件,使樣式和邏輯的關注點得到統一。該領域中的新秀,諸如JSS、emotion和styled-components,依靠工具來將CSS-in-JS程式碼轉化成獨立的CSS樣式表,從而適合在瀏覽器裡執行。
UI控制元件庫提供諸如Grid、Calendar、Panel、Scheduler等Web控制元件,常見的如Sencha Ext JS、jQuery UI、KendoUI、ant.d(螞蟻金服出品)等。除了基礎控制元件庫,還有動畫庫如Popmotion,圖示庫如Font Awesome等。
資料視覺化庫提供各種統計圖表,如bar chart、timeseries chart、pie chart等,比較有名的是Highcharts和百度開源的Echarts,前者基於SVG,後者基於Canvas。如果這兩個庫還不夠用,可以考慮用D3自造輪子。

除此之外,AR/VR/MR也是近些年比較熱的話題,相關技術在遊戲娛樂、醫療影像等場景得到越來越多的應用。2017年10月W3C 的WebVR組釋出了 WebVR 規範1.1版的初稿,2.0版本正在修訂中。與此相關的JS框架、庫包括:A-Frame,AR.js,Three.js,Babylon.js等。

5. 模組化和打包

一開始,Web應用還沒有這麼複雜,JavaScript根本沒有模組化的概念,算得上封裝的只是function和object,立即執行函式(IIFE)達到了封裝私有變數的目的,避免了全域性變數受到檔案內變數的汙染。隨著前端應用的發展,命名衝突、依賴複雜導致的問題迫使人們開始考慮模組化的問題。模組系統將互相依賴的多個檔案和目錄拆分,所有程式碼都可以按需載入並彼此訪問。
最早,伴隨著node.js的興起,CommonJS成功解決了伺服器端JS的模組化。但是由於其採用同步載入的方式,載入資源會造成瀏覽器的“假死”,所以並不適合Web應用的模組化。後來,AMD(非同步模組定義)成為瀏覽器端模組載入的規範,比較流行的庫是RequireJS。RequireJS要求模組定義使用define關鍵字,如下形式:define(['dep'], function(dep){}),模組匯入使用require關鍵字。可見,RequireJS會預先載入依賴,完成後觸發回撥函式。與RequireJS類似的還有阿里大牛玉伯開發的SeaJS,但模組定義規範不同於AMD,它延續CommonJS規範,稱為CMD(公共模組定義)。可惜的是,玉伯承認“現在可以給SeaJS立碑了”。
ES6之後,JavaScript語言本身終於支援模組化了。不需要將所有程式碼都放在一個IIFE或回撥中,只需要在模組中宣告需要的內容,所有的宣告都被限定在模組的作用域中,對所有指令碼和模組全域性不可見,然後將需要暴露的模組資源使用export關鍵字匯出,當其它模組依賴此模組時再通過import關鍵字匯入。由於出現較晚,ES6的模組化還不太完善(比如按需載入),瀏覽器支援也有限,但可以預見,在不遠的將來,ES內建的模組化將取代第三方庫。
RequireJS/SeaJS可以認為是一種線上“編譯”模組的方案,相當於在頁面上載入一個AMD/CMD規範直譯器。這樣瀏覽器就能解析define,require,exports,module這些關鍵字,也就實現了模組化。而Browserify/Webpack是預編譯模組打包的方案,不需要在瀏覽器中載入直譯器。你在本地直接寫JS,不管是AMD/CMD/ES6風格的模組化,它都能編譯成瀏覽器認識的JS。
Webpack已經成為最流行的打包工具,它為所有的靜態資源提供單一的依賴樹,對JavaScript、CSS等資源進行靈活的操作,並將向瀏覽器傳送內容的數量和次數最小化。其強大之處不僅僅在於它統一了JS的各種模組系統,取代了Browserify、RequireJS、SeaJS的工作,更重要的是它的萬能模組載入理念,即所有的資源都可以且也應該模組化。
Parcel是剛剛出世不久的打包或者說是構建工具,是Webpack強有力的對手。相對於配置複雜的Webpack,它號稱超級快(速度是Webpack的兩倍)、零配置,同時還提供了一個開箱即用的開發伺服器,通過熱更新來支援快速開發。Parcel也有些不完善的地方,如不支援SourceMap,不能剔除無效程式碼(TreeShaking)。

6. 自動化構建

寫完程式碼,在釋出前,還需要進行構建,比如使用了TypeScript等方言,需要用Babel transpile到標準的ES5,如果用到CSS預處理工具如SASS,需要從.scss檔案生成.css檔案,進一步,為了提高前端載入效率,可能需要將js、css等檔案打包壓縮,生成雪碧圖,等等。根據用到的技術和元件不同,構建流程包括的專案也不相同。

grunt和gulp都是前端的自動化構建工具,grunt通過配置驅動,gulp是程式碼流式的處理方式,兩者都有大量的外掛支援各種任務。比較而言,gulp更加簡單易用,上手更快,要優於grunt。
npm script就是在package.json裡面的scripts屬性直接定義需要執行的任務,因為是寫在json檔案裡面,所以適合一些短小精悍的命令。
然而,由於webpack等打包工具代替了自動化構建工具的部分功能,顯得自動化構建工具現在的作用不如以前了。

7. 包管理

曾經,NPM是Node模組的管理器,而Bower是前端模組管理器(另外比較有名的還有spm和component),前後端包管理分工明確。但是經過幾年的發展,Bower四面楚歌,主要問題就是直接從git上拉取原始碼,沒有統一的構建工具,缺少像NPM一樣的registry。現在,官方已經不推薦使用Bower了:

而NPM逐漸有一統JavaScript包管理江湖的趨勢,大多數前端模組都能在NPM上找到。

然而在2017年,NPM的地位受到了Yarn的威脅!YARN 是一個新的包管理工具,它可替換現有NPM客戶端的機制,同時相容NPM登錄檔。如果使用NPM客戶端,根據依賴庫的不同安裝順序,它會在node_modules下得到一個不同的樹結構,這種非確定性的特點可能導致“在我的機器上能工作”的問題。通過將安裝步驟分解為解析、獲取和連結,Yarn 使用確定性演算法和 lockfiles避免了這些問題,從而確保重複安裝的一致性。因為它對已經下載的包進行快取,在持續整合(CI)環境中的構建速度明顯更快。

8. 測試工具

根據功能和作用進行分類:
* 提供測試環境(Mocha,Jasmine,Jest,Karma)
* 提供測試結構(Mocha,Jasmine,Jest,Cucumber)
* 提供斷言功能(Chai,Jasmine,Jest,Unexpected)
* 生成,display和watch測試結果(Mocha,Jasmine,Jest,Karma)
* 生成和比較元件和資料結構的快照,以確保以前執行的更改(Jest,Ava)
* 提供mocks,spies和stubs(Sinon,Jasmine,enzyme,Jest,testdouble)
* 生成程式碼覆蓋率報告(Istanbul,Jest)
* 提供一個瀏覽器或類似瀏覽器的環境,控制他們的場景執行(Protractor,Nightwatch,Phantom,Casper)
另外,Storybook 是一個用於定義、開發、測試UI元件的環境。讓你可以建立和測試你的UI元件,就像一個線上的UI樣式指南,對開發者非常有用。

9. 前後端協議

HTTP是Web應用最主要的前後端通訊協議,目前應用廣泛的Restful API也是基於HTTP協議的。當前主流的協議版本是1.1,誕生於1999年,當時Web應用資料互動還沒有現在這麼大,這麼頻繁,但是到了Web2.0時代,HTTP1.1的一些問題就暴露出來,比如連線無法複用和線頭阻塞(Head-of-line blocking),這些問題導致HTTP請求時延過大,使用者體驗差。
為解決這些問題,開發者首先是在應用層面對資料進行優化,比如通過構建對靜態資源進行打包壓縮,小圖片生成雪碧圖等方式,將多個檔案合為一個,減少請求數以優化整個頁面的載入速度。另外為規避HTTP同域請求數的限制,將靜態資源部署在不同的域名上。在協議層面,人們通過建立HTTP長連線、http streaming、web socket等方式減少重建TCP連線帶來的開銷。
所有這些措施都只能是一些優化,沒有根本解決問題的根源。2012年,Google提出了SPDY方案,後來在此基礎上,IETF提出了HTTP2.0的方案。HTTP2.0首先解決了連線共享,即多路複用的問題,同時包括頭壓縮、二進位制格式等特性,這些使得在請求數量大的場景下,頁面載入速度大大提升。HTTP2.0正在不知不覺中普及,但在一段時間內會與1.1版本共存。
SOAP協議在SOA架構中曾經被廣泛使用,但相對於其厚重,在Web2.0時代, 輕量級的REST架構成為主流,並在效能、效率、使用方便性上優於SOAP。REST最大的功勞在於前後端分離與無狀態請求,而REST資源化的請求方式只適合面向簡單的請求,對於具有複雜資源間關聯關係或者個性化的請求就有點無能為力。在一些微服務化了的應用中,為了避免前端向多個微服務同時請求資料然後再組合,不得不增加一個data-view的後端微服務專門用於資料的抽取、轉化。
GraphQL是Facebook推的標準,與之前Netflix的Falcor一樣,都致力於解決上述問題,即:如何有效處理不斷變化的Web/Mobile端複雜的資料請求。GraphQL可以讓使用者在內容和反饋資料的粒度兩個方面掌握更多的控制權,但將更多的職責推到了服務層,必須要在服務端搭建符合 GraphQL spec的介面,改寫服務端暴露資料的方式。

一些公司已經採用GraphQL,如Yelp、Spotify、Github等。GraphQL相關的類庫有Meteor團隊推出的Apollo Data以及Facebook自己推出的Relay。
上面這些技術的分類劃分並沒有嚴格的標準,而且這些分類也無法覆蓋Web前端應用的所有問題域。上面有些框架跨越多個問題域,解決了相關的一系列問題,而有些工具則從不同角度或用不同方式解決相似的問題。Web前端應用場景的增加、規模的擴大以及技術的發展將會催生更多更新的框架、庫,甚至出現新的前端設計理念,如“關注點混合”,“微前端”,“Web3.0”等,顛覆現有技術。

總結

隨著“大前端”概念的興起,前端開發已經超出了傳統Web應用範疇,包括移動應用、VR甚至微信小程式等都納入了前端範疇。前端生態空前興盛,前端語言、框架之多跟後端相比有過之而無不及,本文僅對傳統的Web前端生態做了粗淺的概括,限於篇幅,並不包括移動端Web應用及Web構建桌面應用等相關技術,希望能夠起到一點提綱挈領的作用。最後,用一張思維導圖完成總結:



參考資料:
知乎,medium,segmentfault,hackernoon,微信公眾號,還有很多… …