同形的JavaScript:Web應用的未來
在Airbnb,這幾年我們已經學習了很多了關于構建富應用的經驗,從2011年通過做我們的網站手機版,我們開始研究single-page應 用,尤其是在我們正式推出Wish Lists和我們重新設計的search page以后。大部分都是大型JavaScript項目,這意味著大部分代碼要在瀏覽器中運行這也是為去適應一個更現代的交互體驗。
在現在,這種方法是很普遍的,現在的一些知名的框架(Backbone.js, Ember.js, Angular.js)很容易讓開發者構建一些富應用程序。我們已經發現,無論怎么樣,這些應用都會有一些限制,要想知道為什么,我們先來看一下Web apps 的歷史。
JavaScript Group Up
自Web起初, 瀏覽器是這樣工作的:瀏覽器將會請求一個特定的頁面(例如:請求http://www.geocities.com)使服務器產生響應并生成HTML頁面 然后通過Internet發送回來, 這種工作方式在當時已經是很好的了是因為那時的瀏覽器不是很強大,HTML頁面大多數都是獨立且靜態的文件。JavaScript 的來臨可以使Web頁面變得動態,不僅僅只是實現圖片幻燈片和日期控件。在個人電腦高速發展的今天, 一些牛B的程序員已經擺脫了Web的限制,瀏覽器也在不斷的進化。現在,Web 已經是一個成熟并具有強大功能的應用平臺,包括快速的JavaScript運行,和支持HTML5標準可供開發人員創建一個功能強大富應用程序. 在這以前它僅僅只是普通的本地平臺。
The Single-Page App
很快,利用這些新功能開發人員開始使用JavaScript構建整個網站,這些經典的單頁面應用像 Gmail 能快速的響應用戶行為, 而不是只為了渲染頁面就往返服務器。
一些成熟框架例如: Backbone.js, Ember.js, Angular.js 通常也會被當做“MVC or MVVM模式”的框架而討論, 這個經典的MVC模式看起來像這樣:
大部分的邏輯都在客戶端,(視圖,模版,控制,數據處理,國際化等)為數據提供處理接口, 服務器端可以使用任意一種語言編寫, 如 Ruby、Python、Java,它最多的也就是提供一個空的HTML頁面, 一旦JavaScript文件被下載,它們將被執行以及在客戶端初始化, 從中獲取數據并直接渲染HTML頁面。
這對于用戶體驗來說是很好的, 因為一旦應用初始化并加載,它是可以支持頁面與頁面之間快速切換而不是通過刷新頁面, 在往好了說,它甚至可以實現離線操作功能。
這對開發人員也是很好, 因為它可以明確的為 “client”/”service”分出界線, 從而促進整個開發流程, 可以有效的防止兩種語言這間的實現邏輯重復, 因為前后端通常是使用不同語言開發的。
Trouble in Paradise
實際上, 無論如何它都是有缺陷的, 不過我們可以通過一些案例來正確的避免。
SEO
如果一個應用只運行在客戶端的話是不能通過HTML進行”爬蟲”的,所以它默認是不可被SEO的(搜索引擎優化), 正常我們的爬蟲是通過向服務器創建個請求然后解析結果;但如果服務器返回個空頁面, 那就沒有意義了. 但也不是沒有解決的辦法。
Performance
同理, 如果服務器不能直接渲染整個HTML頁面,而是通過JavaScript去做這些事兒,用戶將會在加載完整個頁面之前看到幾秒鐘的空頁面或者一直加載控 件. 有很多研究表明用戶對訪問慢站點反應很強烈。Amazon claims亞馬遜聲稱 “每提升100ms的頁面加載速度將會提升1%的收入” Twtter 40個工程師花費的1年時間去重構,他們的站點(在服務器端渲染頁面,而不是在客戶端) 聲稱提高了5倍的加載時間。
Maintainability
在理想情況下我們在要創建一個分層明確低耦合的應用程序, 來避免少量的應用邏輯代碼在前后端重復(通常是前后端使用不同的語言開發). 常見的例子比如 日期/貨幣格式化,表單驗證, 流程邏輯. 可維護性一直都是設計程序必要的也是困難的,特別是對于復雜應用來說。
一些開發人員包括我們自己也被這些問題困擾著 — 通常只有真正在單頁面應用下功夫, 才能清楚它的缺陷在哪里。
A hybrid Approach
到了***,我們想要一個綜合的解決方案: 我們想從服務器獲取整個HTML(高必性能, 可SEO) 但我們還想使客戶端代碼運行快速且具有靈活性。
為此, 我們已經在Airbnb嘗試使用”Isomorphic JavaScript”進行構建. 這是一個可以在客戶端和服務端都運行的JavaScript應用. 一個“isomorphic”應用看起來是這樣的, 這里稱為“Client-server MVC”。
在這個世界里, 你的應用和視圖層邏輯都可以在前后端運行, 這樣就依次解決上述所有問題 — 性能優化, 好的維護性, 可以被SEO,更有狀態的Web應用。
通過Node.js,一個快速的, 穩定的運行在服務器端的JavaScript, 現在我們可以夢想成真. 通過創建適當的抽象, 我們就可以在服務器端和客戶端運行我們的邏輯代碼 — 這就是“isomorphic JavaScript“的定義。
Isomorphic JavaScript in the Wild
這不是一個新的想法, 早在2011年 Nodejitsu 已經對 isomorphic JavaScript 有了一個很好的描述- 但現在它才被采用. 現如今已經有很多的 isomorphic JavaScript的框架了。
Mojito 是***個開源的 isomorphic JavaScript框架, 你可以通過任意途徑得到它. 它完全用Node.js寫的框架. 但自從他們在2012年4月開源以來在JavaScript社區沒有廣泛的流行起來主要原因是它依賴于 YUI 和 雅虎特殊的模式。
Meteor 可能是現今***的 isomorphic 項目. Meteor 原生的支持實時應用, 這個團隊正在圍繞這包管理器和開發工具來構建一個完整的體系。
像Mojito,它是一個大型的, 原生的Node.js框架, 它在JavaScript社區里也是工作很好的.,而且1.0 release版本也將要發布了。 Meteor做為一個項目一直被密切關注著 — 它有一個全明星團隊, 并在安德森基金會獲得 $11.2M 資金 – 從未聽說過有公司會對一個開源產品這么關注。
Asana, 是一個任務管理應用 有意思的是它是由 Fackbook 創始人之一的 Dustin Moskovitz創建的. Moskovitz’ 地位乃是世界最年輕的億萬富翁, Asana花費了很多年在開發他們的閉源項目Luna, 這是isomorphic JavaScript***的例子之一。Luna, 在沒有Node.js以前它是構建在v8cgi上, 它允許為每一個單獨用戶會話copy一個完整的應用程序到服務器端運行. 它為每個用戶創建獨立的進程, 運行在客戶端上的也是服務器端的代碼, 開啟對整個類的高級優化, 比如 離線支持 即時更新。
在早些時候我們推出了一個 同構庫它叫被叫做Rendr庫, 它允許你使用 Backbone.js + Handlebars.js 構建單頁面應用, 在服務器端也能全部被渲染。Rendr是我們在為了使 Airbnb mobile web 有更快的響應速度而創建的產品。對于用戶來說高可用的響應速度是尤為重要的. Rendr力求成為一個庫而不是一個框架, 所以它相比Mojito或Metetor來說, 它解決的問題相對來說是少的,但它很容易修改和擴展。
Abstraction, Abstraction, Abstraction
這往往對一些大的項目來說是很困難的, 客戶端與服務器端是完全不同的運行環境,所以我們要創建一系列抽象把解藕的應用邏輯從底層抽出來, 所以我們可以像開發人員暴露一些單獨的API。
Routing
我們想從URI模式路由處理器中獲取單獨的一組路由,我們的路由處理需要訪問HTTP頭, cookies, URI信息, 和特殊的重定向(不是通過window.location或者Node.js 的req res)。
Fetching and persisting data
我們想要描述一個資源就需要渲染一個指定頁面,或者通過抓取組件的形式。 這個資源描述符可以是一個簡單的URI去指向一個JSON數據, 或指向更大的應用程序, 通過模型、集合、指定的模型類或者是一個主鍵KEY對封裝資源是很有用的 , 通常這些在某種程度上都被解析成一個URI。
View rendering
我們是否選擇直接操作DOM, 還是使用HTML模板,或者操作一個封裝DOM的抽像UI組件,來生成一個HTML標記,我們也能在前后端夠渲染任何頁面, 這要看你的應用是否需要了。
Building and packaging
到現在為止也只是走了一半的路程, 工具像 Grunt 和 Browserify 是在啟動和運行應用程序工作流程中不可缺少的.。下面是構建的幾個步驟: 編譯模板 ,包括一些客戶端依賴、 應用混淆、 壓縮等。這個簡單的例子是合并所有應用代碼、視圖和模板捆綁在一起, 但對于大型應用來說會有幾百KB的下載。一個***的辦法是去創建一個動態捆綁和采用延遲加載, 無論怎么樣它都是很復雜的。 靜態統計工具像Esprima可以使一些有上進心的程序人員去嘗試進行再一步的優化以及使用 metaprogramming (元程序)來減少代碼.
Composing Together Small Modules
Isomorphic 框架要想走入市場意味著你要立刻解決所有的問題,但這樣會導致一個大的笨重的框架, 會很難被推廣和很難融入現有應用程序。現在有很多的開發人員已經解決這個問題,我們將會構建一個輕量級的-可復用的-可繼承的 isomorphic 程序。
事實證明大多數的JavaScript模塊不用怎么修改就可以被同構, 例如:現流行的庫像 Underscore, Backbone.js, Handlebars.js, 重要的是 現在甚至jQuery也可以在服務器端使用。
為了證明這一點,我已經構建一個簡單的應用 “isomorphic-tutorial”你可以去Github上去下載。通過將幾個模塊結合在一起, 其中每個模塊都是可同構的,它 僅僅使用幾百行代碼就很容易創建一個簡單的同構應用,它是使用Diretor為服務器端與瀏覽器提供路由,Superagent提供HTTP請求和使用 Handlebars.js做頁面模板,這些所有有構建都是基于Express.js框架,當然作為一個應用組建起來是很復雜的,必須得引入更多層次的抽 象,但是我們希望會有更多的開發人員進行更多的嘗試,它們將會有一個新的庫和新的標準誕生。
The View From Here
更多的機構已經在他們的產品中使用Node.js了,這也就不可避免會有更多的應用開始在前后端共享代碼。 最重要的是要記住 “同構JavaScript”是一個范圍 — 它開始只能共享模板,之后管理整個項目的視圖層,再到大多數應用的業務邏輯層。事實上JavaScript代碼共享在前后端是要取決于你的程序設計,以及 它的獨特約束。
Nicholas C. Zakas 有一個很好的文章“如何將UI層從客戶端拿到服務器端” 提高性能與可維護性。一個應用不需要用Node.js去代替整個后端,這好比 “在倒洗澡水時把小孩也給倒掉了”,反而要想去創建一個好的API和一個RESTful resources(這里推薦阮一峰的一篇文章來簡單介紹什么是 RESTful resource) 的程序,傳統后臺是可以和Node.js結合去搭建的。
At Airbnb網站上,我們已經開始使用Node.js一些基礎工具庫 Grunt 和 Browerify 重構我們的客戶端。我們核心的Rails應用可能永遠都不會使用Node.js做替換,但能過這些工具我們很容易使JavaScript與 template共享同一環境。
如果你要這里是***次聽說,在過幾年 一些高級的WEB應用將運行JavaScript在服務器端。
Learn More
如果這個idea使你很興奮,那么你可以來我們的 Isomorphic JavaScript 工作室來看看,在舊金山 11月12日 星期三 或者 11月21日 星期四,我將在DevBeat上教你們 isomorphic JavaScript 如何組裝以及會告訴你們寫一個同構程序是多少容易的一件事 兒。
原文鏈接:http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/