天天看點

用戶端JavaScript架構的五大痛點

更新: 本文原本的标題是“為何我們棄用AngularJS:……”,現在把它去掉了。因為這些痛點主要是針對單頁JS應用架構的。有些人認為本文是專門批判AngularJS的,這可不是我的本意。-- Quinn

幾個月前我們的

Sourcegraph 網站向公衆開放,它是一個富 AngularJS

應用。伺服器傳輸原始的HTML頁面和JSON端點,剩下的就交給Angular來處理。這是一個建立Sourcegraph的簡易方式,當時我們不知道Sourcegraph會變成什麼樣。

但是單頁JavaScript架構并不适用于每一個站點。Sourcegraph是一個内容為主的站點,我們漸漸發現富js應用弊大于利。富js應用的好處衆所周知,下面是我們體會到的一些意料之外的困難。希望對面臨類似選擇的開發人員能有一些幫助。

用戶端JS架構的5個痛點

我們早知道會面臨很多的困難,但是不知道會有這麼難。

1. 糟糕的搜尋排名和Twitter/Facebook預覽

用戶端JavaScript架構的五大痛點

搜尋引擎爬蟲和社交網站的預覽抓取器不能加載純Javascript站點,提供替代版本又慢又複雜。

有兩種方式可以允許爬蟲閱讀你的站點。你可以在伺服器端運作一個浏覽器執行個體來執行你的應用裡的Javascript,然後從DOM中卸下HTML(使用

PlantomJS

或者

WebLoop

)。或者你可以建立一個服務端生成的專供爬蟲的替代性HTML版本。

第一個方法需要你為每一個頁面加載建立一個headless浏覽器(或者tab),比起直接産出HTML,這樣會花費很多的時間和系統資源。取決于你使用的架構,需要不少精力來決定什麼時候頁面已經準備好了。 你可以緩存頁面,但是如果頁面經常改變,那麼緩存隻能起到非常有限的優化作用,而且會增大複雜度。這個方法會将你的頁面加載速度拖慢好幾秒,對搜尋引擎排名也不利。

第二個方法(建立一個替代性的伺服器端站點)對簡單站點而言足夠了,但是如果頁面很多,這将是一個噩夢。況且如果Google認為你的伺服器版本站點跟你的主站版本有很大的不同,那他就會狠狠的懲罰你。糟糕的是,直到你的通路量直線下降的時候你才會意識到你已經過界了。

2. 不可靠的統計和監控

很多分析工具需要使用易于出錯、手工內建的

HTML5 history API

(pushState)來導航。這是因為它們無法自動檢測到你的應用使用pushState導航到了新的頁面。即使可以做到,它們仍然需要等待你應用的信号來收集新頁面的其他資訊(例如頁面标題和其他頁面特定的名額)。

你如何解決這個問題?同時取決于你的用戶端路由庫和你內建的分析工具。用

Google分析

Backbone.js

?嘗試一下

backbone.analytics

。用

Heap

(順便說一下,Heap很棒)和

UI-Router

?設定你自己的

$stateChangeSuccess

鈎子然後調用

heap.track

還沒完!你想追蹤起始頁面加載?也許你重複跟蹤了?你會跟蹤失敗的頁面加載嗎?如果你使用

replaceState

代替pushState呢?即使要獲知你是否錯誤地配置了分析鈎子——或者是否依賴更新搞亂了系統——也是相當困難的,除非交叉檢查分析。當你發現問題後,很難去恢複你錯過的分析資料(或者消除重複資料)。

3. 緩慢、複雜的建構工具

用戶端JavaScript架構的五大痛點

前端JavaScript建構工具,例如

Grunt

,需要複雜的配置而且會很慢。還好我們有像

ng-boilerplate

這樣出色的項目來幫忙,但是它們很慢。并且如果你想添加一個自定義的步驟的話你還是無法避免複雜性。(我為什麼說Grunt複雜,看看這個

配置檔案

就知道了。)

一旦你配置好了你的應用,包括Gruntfiles等等。你仍然要忍受漫長的JavaScript建構時間。你可以把dev和production建構通道分開來提高開發速度,但是你終将深受其苦。用AngularJS尤其如此,他需要在壓縮代碼前使用

ngmin

(如果你用了

特定功能

)。事實上,我們有幾次就是因為這些壓縮的JavaScript和開發時的代碼表現不同而把SourceGraph搞砸了。

事情正在改善,

Gulp

是一個巨大的提升。

4. 慢,不可靠的測試

用戶端JavaScript架構的五大痛點

測試JavaScript-only的站點需要使用基于浏覽器的測試架構,比如

Selenium

PhantomJS

,或者

。安裝這些(除了PhantomJS)通常意味着安裝WebKit和Java依賴,配置

Xvfb

(雖然

新版的PhantomJS

移除了這些依賴),也許運作一個本地的VNC用戶端和伺服器來測試。最後,你還需要在持續內建伺服器上配置這些東西。

相反,測試伺服器端生成的頁面通常隻需要類庫來擷取URL和解析HTML,安裝和配置要簡單許多。

一旦你開始編寫浏覽器測試,你必須處理異步加載。你不能在頁面還沒有加載的時候就測試頁面上的元素,但是如果在一個特定時間段裡沒有加載,你的測試就會失敗。浏覽器測試類庫提供了一些幫助函數來處理這種情況,但是對于複雜頁面它們隻能幫上一點小忙。

你想組合很重的浏覽器測試工具(Selenium,加上Firefox或者Webkit)和很大的測試複雜度(由于浏覽器測試的異步本性)?你的測試需要很多配置,很長的時間來運作,而且很不可靠。

5. 被掩蓋的未根除的緩慢

在富JavaScript應用中,頁面轉換幾乎是瞬間發生,然後所有的特定元素異步加載。伺服器端應用恰恰相反:頁面在伺服器端加載完成前不會發送到用戶端。

聽起來似乎是用戶端應用勝利了,但是也許這不過是一個僞裝的詛咒。

考慮用戶端JS應用,當使用者點選一個連結,頁面會立刻加載并呈現。如果使用者導航到一個側邊欄需要5秒鐘才可以加載的頁面,第一眼感覺很快,但是如果使用者需要的資訊在側邊欄裡,對使用者來說就太慢了。即使你需要的特定内容能立即加載,你仍需要忍受轉動的加載訓示器和頁面填充時的抖動。

現在考慮一下這樣的情況:如果開發人員想在那個頁面添加新功能。很難确定這個功能是否必須快速加載——因為一切都是異步的,是以誰會在意頁面底部過了幾秒才加載呢?如此反複幾次,整個站點就會讓人覺察到遲緩和抖動。

在伺服器端應用中,如果一個API調用很慢,整個頁面就會阻塞直到頁面完成。伺服器端的緩慢不可能被忽視,因為這很容易被測量,并且會公平地影響每一個人。但是在用戶端應用中這很容易被忽略。

你可以争論說,一個好的開發團隊應該避免這些錯誤,并且用戶端 JS 架構不是罪魁禍首。這是對的,但是總體上來說,用戶端JS架構降低了遲緩的開銷。這一點觸動了開發團隊的激勵機制。

接下來怎麼辦?

上面說的問題,本身都不算大問題。我們可以做很多工作來減輕上述情況(事實上我們确實做了很多)。但是,這些問題加在一起就是另一回事了,可以說,用戶端JS架構成為了我們開發工作的一大負擔。

同時要牢記,每一個站點都是不同的。例如,Sourcegraph是一個内容站點,這意味着頁面在加載後不會有太多的變化(和富應用相比)。我們依然喜愛這些技術,但是它們不是建構我們的主站的合适工具。

繼續閱讀