雖然Angular是一種構建Web應用的強大方式,但是長期以來,開發人員都知道它在SEO和可訪問性方面的限制。當然,Google的爬蟲能夠執行JavaScript,但是它並不是唯一的爬蟲方案。例如,在將一個鏈接提交給Slack之後,它的爬蟲會抓取一個預覽,但是並不會執行JavaScript,所以原始的Angular HTML模板將會顯示在預覽之中。為了消除這種現象所產生的問題,Jeff Whelpley和Patrick Stapleton開發了Angular Universal,它允許在服務端進行渲染。
Universal JavaScript(有時會被誤稱為“isomorphic”)並不是Angular特有的技術。Angular Universal的工作原理是在服務端進行應用的初始化渲染,並將其發送給浏覽器,用戶就能馬上看到了,然後才發送客戶端的JavaScript。這與Angular應用的典型順序是有所區別的,在典型的順序中會首先發送客戶端JavaScript,然後初始化UI才會在客戶端渲染。
Welpley和Stapleton開發Angular Unversal已經超過一年了,在這個過程中發現了六個經常遇到的模式。在2016 ng-conf的分享中,它們主要關注了其中的三項:
事件脫節是在服務端渲染所造成的副作用,在這種方式下,渲染會在JavaScript客戶端腳本發送到浏覽器之前執行。根據JavaScript發送和執行的速度不同,用戶在與UI進行交互的時候,可能代碼還沒有為這些交互做好准備。這種脫節可能會導致用戶交互的丟失。
針對該問題的解決方案就是記錄用戶的事件,並在客戶端JS加載完成之後進行重放。如下的樣例展現這種代碼會是什麼樣子的:
var myEvents = []; var myInputValue; // 記錄客戶端視圖myInput的所有keyup事件 function recordEvents() { var $myInput = document.querySelector('.myInput') $myInput.addEventListener('keyup', function (event) { myEvents.push(event); myInputValue = event.target.value; }); } // 在服務器視圖myInput上回放所有的keyup事件 function replayEvents() { var $myInput = document.querySelector('.myInput'); myEvents.forEach(function (event) { $myInput.dispatchEvent(event); }); $myInput.value = myInputValue; $myInput.focus(); } // 在window加載完成之後,馬上就開始記錄 window.addEventListener('load', recordEvents);
Angular Universal使用一種名為preboot過程來處理這項任務,而不是要求開發人員手動地做這些事情,可以通過如下的標記啟用該功能:
preboot: true
JavaScript在本質上是異步的,在服務端渲染Angular的時候,這就會產生問題。通常的解決方案是使用鏈(chaining)或回調,但要求開發人員重寫他們的代碼來解決這個問題顯然不是好的可選方案。“我們不能這樣做,而是必須要找到一種方式來處理這些不同的異步事件,並調整它們何時將響應發送回來”,Whelpley這樣說到。
Angular Universal使用另外一個標記來解決這個問題,只需一行就可以了:
async: true
將這個標記打開之後,將會使用Angular新的Zones特性,“跟蹤所有的異步調用,並且能夠知道它們何時完成。”
在服務端渲染Angular代碼的第三個主要的問題在於使用平台特定的依賴。例如,localStorage
是浏覽器的特性,在服務器端根本不存在。Whelpley和Stapleton指出,可以使用依賴注入(Dependency Injection,DI)作為解決方案。他們建議根據代碼所執行的上下文,借助DI來替換實現,而不是使用平台具體的特性。
對於測試過他們功能的開發人員來說,這應該不足為奇。Whelpley指出,Angular所運行的測試和其他平台已經證明了這項技術在Angular 2的代碼中將會非常普遍。“平台相關的依賴基本上已經被我們消除掉了。這個模式是我今天所討論的最強大的模式”,Whelpley說道。
他們ng-conf分享的完整視頻已經可以觀看了。
一些AngularJS相關文章鏈接:
AngularJS權威教程 清晰PDF版 http://www.linuxidc.com/Linux/2015-01/111429.htm
希望你喜歡,並分享我的工作~帶你走近AngularJS系列:
如何在 AngularJS 中對控制器進行單元測試 http://www.linuxidc.com/Linux/2013-12/94166.htm
在 AngularJS 應用中通過 JSON 文件來設置狀態 http://www.linuxidc.com/Linux/2014-07/104083.htm
AngularJS 之 Factory vs Service vs Provider http://www.linuxidc.com/Linux/2014-05/101475.htm
AngularJS —— 使用 ngResource、RESTful APIs 和 Spring MVC 框架提交數據 http://www.linuxidc.com/Linux/2014-07/104402.htm
AngularJS 的詳細介紹:請點這裡
AngularJS 的下載地址:請點這裡
查看英文原文:3 Development Patterns of Angular Universal