本文首發于 vivo網際網路技術 微信公衆号
連結: https://mp.weixin.qq.com/s/VRSl5_yn5BZcqtRxWkXU-Q
作者:孔垂亮
一、什麼是前端
回答這個問題之前,我想起了一道非常經典的前端面試題:“從輸入URL到頁面呈現在你面前到底發生了什麼?”這個題目可以回答的很簡單,但仔細思考,也可以回答的很深,這個過程涉及的東西很多。先看一張圖:

簡單說就是
- DNS (Domain Name System) 解析
- TCP (Transmission Control Protocol) 連結
- HTTP (HyperText Transfer Protocol) 請求
- HTTP 響應
- HTML解析 & CSS渲染
- JS 解析執行
為什麼提這個呢,因為這是一整個web服務生命周期的全過程,而在最早的時候是根本沒有前端或者後端的概念的。當時就是用 Dreamweaver 寫 html 靜态頁面,然後部署到一台電腦的 IIS (Internet Information Services) 上。當請求這個頁面時,傳回這個 html 檔案。
再後面一點,服務端變得複雜了一些,html 頁面開始使用各種模闆來寫,譬如 Java 系列的 FreeMarker,還有 ASP 、 PHP 等等。此時,前後端開發是一體的,最多也就是模闆的編寫算是最初的前端範疇,但那個時候,這個活兒往往都是現在的後端開發去幹的。
下面是一個比較典型的 PHP 的模闆:
<html>
<head><title>Car {{ $car->id }}</title></head>
<body>
Car {{ $car->id }}
<ul>
<li>Make: {{ $car->make }}</li>
<li>Model: {{ $car->model }}</li>
<li>Produced on: {{ $car->produced_on }}</li>
</ul>
</body>
</html>
随着 2005年 Ajax (Asynchronous JavaScript and XML) 的誕生,徹底得改變了這一切。JS 腳本可以獨立向伺服器請求資料,拿到資料後,進行處理并更新網頁,這個過程中,後端隻負責提供資料,其他事情都由前端來做。就是從這個時期開始,前端逐漸變得複雜,也是從在這個時期開始,設計師和後端開發已經開始放棄前端了,開發的崗位角色悄悄地發生了變化:
聊到現在,什麼是前端的問題應該呼之欲出了:
- 前端:針對浏覽器的開發,代碼在浏覽器中運作
- 後端:針對伺服器的開發,代碼在伺服器中運作
可以說 Ajax 的出現是前端崗位出現的轉折點,但并不是前端的起點,前端的起點,我們稍後聊 JavaScript 的曆史會聊到。
既然前端是針對浏覽器的開發,那一個頁面呈現出來,在浏覽器裡做了什麼呢?
浏覽器收到伺服器響應的 HTTP 封包後,邊解析邊渲染。首先浏覽器解析 html 檔案建構 DOM 樹,然後解析 CSS 檔案建構渲染樹,等到渲染樹建構完成後,浏覽器開始布局渲染樹并将其繪制到螢幕上。除了表現之外,我們還需要與頁面互動,是以離不開 JS,而 JS 的解析和運作是由浏覽器中的 JS 引擎來完成,最有名的就是2008年由 Google 釋出的 V8。
是以,跑在浏覽器的代碼無外乎這三種:HTML + CSS + JS。
HTML(HyperText Markup Language) 全稱是超文本标記語言,它不是一門程式設計語言,而是一種用來告知浏覽器如何組織頁面的标記語言。它由一系列的元素(elements)組成,這些元素可以用來包圍不同部分的内容,使其以某種方式呈現或者工作。
我們在浏覽器中任意打開一個頁面的源碼,都會看到類似如下的内容:
CSS(Cascading Style Sheets) 全稱是層疊樣式表,它是用來樣式化和排版網頁的 —— 例如更改網頁内容的字型、顔色、大小和間距,将内容分割成多列或者加入動畫以及别的裝飾型效果。它通過選擇器選中上面提到的 HTML 元素,然後為選中的元素添加顔色,間距等樣式。如下所示:
每一個有追求有品味的頁面,都在借 CSS 給浏覽者說一句話:"我怎麼這麼好看!"
JS(JavaScript) 是一種具有函數優先的輕量級、解釋型程式設計語言。它因網際網路而生,緊跟着浏覽器的出現而問世。它是一門計算機語言,随着前端的迅猛發展,它已經不像剛開始出現時那樣,隻是為了做了一些頁面的校驗,已經成了建構企業級應用的重要語言之一,目前在全球範圍的使用情況排名第三。
如果用一個人來作比喻網頁的話,HTML 就是一個人的骨骼, CSS 就是一個人的血肉,而 JS 則是一個人的靈魂!
前端開發工程師 是近十年随着前端發展才真正開始受到重視的一個新興職業。剛才我們提到前端的三個組成部分:HTML + CSS + JS,這三個部分看起來聽起來都感覺很簡單,也正因為如此,前端開發領域有很多自學成“才”的同行,我甚至在校招面試時聽到候選人說是因為覺得後端太難,其它崗位面試通不過才選擇前端的。
确實,前端開發的入門門檻低,與後端語言先慢後快的學習曲線相比,前端開發的學習曲線是先快後慢,後面的學習曲線越來越陡峭,每前進一步都很難,導緻大多數前端開發都停留在初級階段。
二、JavaScript 語言的曆史
JS 作為網頁的靈魂,它是前端開發中最重要的一部分,是以接下來我們來看看 JavaScript 作為一門計算機語言是怎麼誕生的,又經曆了怎麼樣的發展。
1990年12月,歐洲核子研究中心(CERN)的科學家 Tim Berners-Lee 發明了網際網路(World Wide Web),2019年的3月12日,歐洲核子研究中心還舉辦了系列活動,慶祝網際網路發明三十周年。當時的網頁還隻能在作業系統的終端裡浏覽,也就是說隻能使用指令行操作,網頁内容都是在字元視窗中顯示,這當然非常不友善。
1994年5月中科院高能實體研究所計算中心的許榕生研究員去 CERN 參加了由380人參加的第一屆國際 WWW 大會。會後,他帶領一批年輕人很快在高能所計算中心的一台 PC 機上用 Linux 建立了中國第一個 WWW 伺服器,并推出第一個網站 www.ihep.ac.cn (這個域名現在還在使用) 和英文網頁(IHEP/China Home Page),該網站成為當時亞洲少數幾個網站之一。
1992年底,美國國家超級電腦應用中心(NCSA)開始開發一個獨立的浏覽器,叫做 Mosaic。這是人類曆史上第一個浏覽器,從此網頁可以在圖形界面的視窗浏覽。Mosaic 是後來大家耳熟能詳的網景浏覽器(Netscape Navigator)的前身。
那時候還沒有 Ajax,是以使用者每次操作,都會重新加載整個頁面。于是 Netscape 公司很快就發現一個問題,如果使用者還沒有輸入内容,就點了“發送”摁鈕,伺服器發現後把整個頁面重新傳回給用戶端,僅僅隻是在頁面中添加了一個錯誤提示。
那個時代網速很慢上網很貴,到伺服器才發現這一點很明顯太晚了,最好能在使用者發出資料之前,就告訴使用者“請填寫内容”。這就需要在網頁中嵌入小程式,讓浏覽器檢查每一欄是否都填寫了。
1995年4月,Netscape 公司雇傭了程式員 Brendan Eich 開發這種網頁腳本語言,Brendan Eich 隻用了10天,就設計完成了這種語言的第一版,最初名字叫做 Mocha,1995年9月改為 LiveScript。12月,Netscape 公司與 Sun 公司(Java 語言的發明者和所有者)達成協定,後者允許将這種語言叫做 JavaScript。
這樣一來,Netscape 公司可以借助 Java 語言的聲勢,而 Sun 公司則将自己的影響力擴充到了浏覽器。實際上 JavaScript 與 Java 沒啥太大關系!
1996年8月,微軟模仿 JavaScript 開發了一種相近的語言,取名為JScript(JavaScript 是 Netscape 的注冊商标,微軟不能用),首先内置于IE 3.0。Netscape 公司面臨喪失浏覽器腳本語言的主導權的局面。
于是,Netscape 公司在1996年11月決定将 JavaScript 送出給國際标準化組織 ECMA (European Computer Manufacturers Association), 希望 JavaScript 能夠成為國際标準,以此抵抗微軟。
1997年7月,ECMA 組織釋出262号标準檔案(ECMA-262)的第一版,規定了浏覽器腳本語言的标準,并将這種語言稱為 ECMAScript。
之是以不叫 JavaScript,一方面是由于商标的關系,Java 是 Sun 公司的商标,根據一份授權協定,隻有 Netscape 公司可以合法地使用 JavaScript 這個名字,且 JavaScript 已經被 Netscape 公司注冊為商标,另一方面也是想展現這門語言的制定者是 ECMA,不是 Netscape,這樣有利于保證這門語言的開放性和中立性。
是以,ECMAScript 和 JavaScript 的關系是,前者是後者的規格,後者是前者的一種實作。在日常場合,這兩個詞是可以互換的。
接下來的兩年,連續釋出了 ECMAScript 2.0(1998 年 6 月)和 ECMAScript 3.0(1999 年 12 月)。3.0 版是一個巨大的成功,在業界得到廣泛支援,成為通行标準,奠定了 JavaScript 語言的基本文法,以後的版本完全繼承。直到今天,初學者一開始學習 JavaScript,其實就是在學 3.0 版的文法。
2000年,ECMAScript 4.0 開始醞釀。這個版本最後沒有通過,但是它的大部分内容被 ES6 繼承了。是以,ES6 制定的起點其實是 2000 年。為什麼 ES4 沒有通過呢?因為這個版本太激進了,對 ES3 做了徹底更新(也就是現在的ES6),引來了以 Yahoo、Microsoft、Google 為首的大公司的強烈反對,ECMA 開會決定,中止 ECMAScript 4.0 的開發。
隻有 JavaScript 的創造者 Brendan Eich 所在的 Mozilla 公司 堅持ES4的草案,有時候要創點新真得不容易!
2015年6月,ECMAScript 6 正式釋出,并且更名為“ECMAScript 2015”。雖然從ES3之後,陸續發了 ES5 以及 ES5.1,但都是涉及現有功能改善的一小部分。
對于前端開發來說,接受并熟悉 ES6 是比較困難的,畢竟當年 Google 就接受不了,何況 ES6 是集過去15年的精華于一身。
三、Web開發技術演進
聊完 JavaScript 的曆史,我們可以看到,它并不随前端的發展呈正相關,因為它在很長一段時間,并沒有什麼變化。是以接下來聊聊前端技術演進的曆史,看看這些年前端都發生了什麼。
1.Web 2.0
前面提到的 2005 年誕生的 Ajax,促進了前後端的分離。
其實是在這一年Google釋出了測試版本的Google地圖,并在這個項目大量運用讓網頁透過 Javascript 以 XML 格式來回傳資料、達到異步更新網頁内容的技術。
這在當時是一個跨時代的壯舉,讓使用者終于有機會看到不需要重新整理整個頁面就可以更新狀态的地圖,我們也看到了異步操作是如何給網站使用者帶來良好體驗的。
不誇張的說,這一年算得上是 Web 開發技術發展的元年。Web也從 1.0 的時代,步入 2.0 的時代。
2.MVC (model-view-controller)
前端可以通過 Ajax 擷取資料,是以也就有了處理資料的需求,于是就促使了前端 MVC 的誕生。
我第一個前端項目就是使用 MVC 模式做的,使用的是 ExtJs,它曾經是一個很好的企業級 Web 富用戶端應用開發平台,它做出來的頁面效果特别酷炫。如下圖所示:
而我在做這個項目時就應用了 MVC 的模式。
- 視圖(View):使用者界面
- 控制器(Controller):業務邏輯
- 模型(Model):資料模型
View 作為使用者界面,發送指令給 Controller,Controller 要求 Model 改變狀态,同時 Model 把更新過的資料發送給 View 回報給使用者。
MVC 模型最核心的一點就是 所有通信都是單向的。
其實生活當中,MVC 的設計思想很多地方都有所展現,以家用微波爐為例,可以将它也了解成三層結構。微波爐的外觀以及上面的操作摁鈕就是"視圖層"(view),而其内部的微波産生裝置磁控管則是"資料層"(Model),這裡的"資料"可以了解成"核心功能"。把操作摁鈕的指令轉化為對磁控管的操作則是由“控制器層”的電路闆來實作的。
如果現在要給微波爐更換一個新潮的外殼,或者更換一個更大功率的磁控管,完全可以在不更改其他層的情況下實作。每一層都是獨立的,這就是 MVC 模式的最大優勢。
在這個階段的後期,前端逐漸開始有了一點工程化的影子,并且開始受 CommonJS 的影響,有了子產品化程式設計的概念,誕生了相應的 CMD 和 AMD 的規範。開始有了建構工具 Grunt/Gulp,開始有了編碼的規範 JsLint。
3.MVVM (Model-View-ViewModel)
MVVM 同樣是一種軟體架構模式,它是在 MVC 的基礎上演進過來的,去掉了 MVC 中的 Controller,增加了資料的雙向綁定。
最有代表性的架構就是 Google 公司推出的 Angular, 它的風格屬于 HTML 語言的增強,核心概念就是資料雙向綁定。
Vue也可以算是 MVVM 模型,雖然它沒有完全遵守 MVVM 的設計,但受到了 MVVM 的啟發,在最開始的時候也是雙向資料綁定,并且一直使用 vm 表示 View-Model。就以 Vue為例,簡單看下 MVVM 的思想。
4.SPA (single-page application)
SPA 是單頁應用的意思,它是區分傳統模式而言的。我們一開始就探讨過從輸入URL到頁面呈現在我們面前的過程,也熟悉了 HTML 、 CSS 和 JS。現在換個角度來看這個過程:
當用戶端發起頁面請求後,後端收到請求,然後取出資料庫中的資料,組裝好 HTML,然後傳回 HTML 、 CSS 和 JS。有了 Ajax 後,我們在目前頁面可以重新擷取資料,并更新頁面内容。但當我們切換頁面,也就是有頁面跳轉時,整個過程會從頭再來一次。
精益求精的前端開發者們這個時候就在考慮,既然 Ajax 可以在目前頁面擷取資料并随時更新目前頁面,那是不是可以做到切換頁面時也隻通過 Ajax 擷取資料更新頁面,而不全部重新加載呢?
答案當然是可以!如下圖所示,使用者第一次發起頁面請求時,後端收到請求,然後取出資料庫中的資料,傳回 CSS 和 JS檔案。
JS 檔案包括了頁面切換邏輯的處理,這是單頁應用實作的關鍵,它利用 Hash 或者 History 的技術,實作了當切換頁面時,首先通過 Ajax 擷取到新頁面需要的資料,然後由 JS 根據要切換到的網址,使用擷取到的資料來拼接出要展示頁面的 HTML。
整個切換頁面的動作全部由前端來完成了。這就是單頁應用,所有的資源隻在第一次頁面請求時被加載,後面都隻會發起 Ajax 請求擷取資料而已。
**5.* (server side render)
SPA 讓 web 變成了應用的形态,它是用戶端渲染(client side render)。用戶端渲染有它的弊端,譬如沒法做 SEO(Search Engine Optimization),由于所有的 JS 和 CSS會在首次通路時被全部加載,并且 HTML 是在前端組裝的,就勢必導緻首屏加載以及渲染的時間會增加,影響使用者體驗。
于是,現在又争先恐後的回到服務端渲染,想想真得挺可笑的,十年前為了搭上 Ajax 的班車紛紛做SPA,做用戶端渲染,現在反而又想着法兒的要重新做服務端渲染。
其實本質是一樣的,是以這裡其實是有曆史包袱的,在項目開始之前,先想想清楚到底有沒有必要做成 SPA 比較重要,而不是一味的趨之若鹜。
當然現在的服務端渲染和之前的服務端渲染在形式上還是有差別的:
之前的服務端渲染基本是圍繞頁面為中心的開發模式,隻需要處理 模闆-\> html字元串的轉換,性能要優于現在的服務端渲染。
現在的服務端渲染基本是圍繞元件為中心的開發模式,開發效率和可維護性當然更高,元件也可以統一通過子產品建構工具如webpack一并處理。
有一些 web 應用如果就應該使用 SPA 模式,但又想要 SEO 怎麼解決呢?
當搜尋引擎的網絡爬蟲過來的時候,其實是可以通過頭資訊判斷的,于是有一種創新的解決方案,可以在中間層寫個服務,對請求進行攔截。
譬如 Rendora 就是解決這個問題的,之前寫好的項目一句不用改,隻需新起 Rendora 服務,對于爬蟲的請求額外增加服務端渲染,傳回生成好的 html 就好了,對于非爬蟲,之前該怎麼玩兒就怎麼玩兒。
6.Node & 全棧
2009年,Node 項目誕生,它是伺服器上的 JavaScript 運作環境。Node的出現令前端開發擁有了控制伺服器的能力:Node = JavaScript + 作業系統 API
下一節聊聊 Node,敬請期待。
四、參考文獻
- JavaScript 語言的曆史
- 大前端的技術原理和變遷史
- MVC,MVP 和 MVVM 的圖示