單頁應用

單頁應用-{zh-tw:動態載入;zh-cn:動態裝載}-適當的資源並新增到頁面。儘管可以用位置雜湊或HTML5來提供應用程式中單獨邏輯頁面的感知和導航能力，但頁面在過程中的任何時間點都不會重新載入，也不會將控制轉移到其他頁面。與單頁應用的互動通常涉及到與網頁伺服器後端的動態通訊。歷史.儘管早在2003年就討論過這個概念，但單頁應用一詞的起源並不明晰。在2002年4月編寫的自主網站slashdotslash.com有著相同的目標和功能；同年稍晚，Lucas Birdeau、Kevin Hakman、Michael Peachey和Evan Yeh在美國專利8,136,109中描述了一個-{zh-cn:單頁應用程式;zh-tw:單頁式應用程式}-的-{zh-cn:實現;zh-tw:實作概念}-。在網頁瀏覽器中可以使用JavaScript顯示使用者介面、執行應用程式邏輯，以及與Web伺服器通訊。成熟的開源程式庫支援構建一個單頁應用，從而減少開發人員要編寫的JavaScript程式碼量。技術舉措.現今已有各種技術可以使網頁瀏覽器停留在單個頁面，並同時支援應用程式與伺服器通訊。JavaScript框架.諸如AngularJS、Ember.js、、ExtJS和React等-{zh-cn:面向網頁瀏覽器;zh-tw:網頁瀏覽器端}-的JavaScript框架採納了單頁應用原則。Ajax.目前最常採用Ajax技術。主要從JavaScript使用XMLHttpRequest/ActiveX物件，其他Ajax方法包括使用IFRAME或script HTML元素。jQuery等流行的庫可以為不同廠商的瀏覽器的Ajax行為標準化，進一步推廣了Ajax技術。Websocket.WebSocket是HTML5規範中的一個雙向有狀態實時客戶端與伺服器通訊技術，在效能和簡單性方面優於Ajax。伺服器傳送事件.是一種伺服器向瀏覽器客戶端發起資料傳輸的技術。一旦建立了初始連線，事件流將保持開啟狀態，直到客戶端關閉。該技術透過傳統的HTTP傳送，並具有WebSockets缺乏的各種功能，例如自動重新連線、事件ID以及傳送任意事件的能力。瀏覽器外掛.可以使用瀏覽器外掛技術實現對伺服器的非同步呼叫。此種方法在業界已經過時。資料傳輸.對伺服器的請求通常會帶來原始資料或傳回新的HTML。在伺服器返回HTML時，客戶端上的JavaScript將更新DOM的部分割槽域。在返回原始資料時，客戶端側的JavaScript通常將其轉換為HTML，然後用它來更新DOM的-{zh-cn:部分割槽域;zh-tw:部分割槽域}-。伺服器架構.瘦伺服器架構.SPA技術將邏輯從伺服器轉移到了客戶端。這導致Web伺服器發展為一個純資料API或Web服務。這種架構的轉變在一些圈子中被稱為“瘦伺服器架構”，以強調複雜性已從服務端轉移到客戶端，並認為這最終降低了系統的整體複雜性。胖的有狀態伺服器架構.這種設計是伺服器在記憶體中儲存必要的客戶端所處狀態。這種模式下，當任何請求到達伺服器。與此同時更新伺服器中的狀態。這種設計下的大部分邏輯都在伺服器上執行，HTML通常也在伺服器上呈現。在某些方面，伺服器是模擬Web瀏覽器，接收事件並執行伺服器狀態下的增量更改，將這些更改自動傳播到客戶端。這種方法需要更多的伺服器記憶體和處理能力，但優點是簡化的開發模型，因為：1、應用程式通常完全在伺服器中編寫；2、伺服器中的資料和UI狀態在相同的記憶體空間中共享，不需要自定義客戶端/伺服器通訊隧道。胖的無狀態伺服器架構.這是有狀態伺服器方法的變體。客戶端頁面通常透過Ajax請求將表示其當前狀態的資料傳送到伺服器。伺服器使用這些資料能夠重新構建需要修改的頁面部分，並生成必要的資料或程式碼，將其返回給客戶端使其它達到新的狀態。此方法需要將更多資料傳送給伺服器，並可能需要更多計算資源才能部分或完全重建在伺服器中的客戶端頁面狀態。不過，這種方法更容易擴充套件，因為伺服器中不存在每個客戶端的頁面資料，因此可以將Ajax請求分派到不同的伺服器節點，而無需會話資料共享或伺服器關聯。-{zh-cn:本地執行;zh-tw:本機執行}-.部分單頁應用可以使用依賴本地檔案執行。這使使用者可以從伺服器上下載單頁應用並在本地裝置中執行，而不需要依賴與伺服器的網路連線。這類單頁應用如果想要儲存或更新資料，則必須使用基於瀏覽器的網頁儲存。這些應用受益於HTML5提供的高階功能。SPA模式帶來的挑戰.由於單頁應用偏離了最初為瀏覽器設計的無狀態頁面重繪模型，所以帶來了一些新挑戰。每個問題都有一個或一些有效的解決方案：搜尋引擎最佳化.由於一些流行的網路搜尋引擎的爬蟲缺乏JavaScript執行能力，搜尋引擎最佳化已成為面向公眾的網站採用單頁應用模型必須面對的一個問題。在2009至2015年間，Google網站管理員提出並推薦了一個“AJAX爬取方案”，其中使用起始為感嘆號的片段識別符號來標識有狀態的AJAX頁面。單頁應用網站必須-{zh-cn:實現;zh-tw:實作}-特殊行為才能允許搜尋引擎的爬取工具提取相關的元資料。對於不支援此URL雜湊方案的搜尋引擎，單頁應用的雜湊網址會被視而不見。包括Jeni Tennison在內的許多作者認為這些“hash-bang”URI在W3C中被認為是存在問題的，因為它們使那些沒有在瀏覽器中啟用JavaScript的人無法訪問頁面。這也影響HTTP參照位址-{zh-cn:頭;zh-tw:標頭}-，因為瀏覽器不允許在Referer-{zh-cn:頭;zh-tw:標頭}-中傳送片段識別符號。2015年，Google不再建議使用雜湊AJAX爬取方案。還有一些周邊方法可以使網站表現為可抓取，它們都涉及建立反應單頁應用內容的獨立HTML頁面。伺服器可以建立基於HTML的網站版本並將此提供給爬取工具，也可以使用PhantomJS等無頭(headless)瀏覽器執行JavaScript應用程式並輸出生成的HTML。這種方法需要付出不小的努力，最終可能給大型、複雜的網站帶來很大的維護成本，並且也有潛在風險。如果伺服器生成的HTML被認為與單頁應用存在較大差異，則網站排名將受到處罰。執行PhantomJS來輸出HTML可能會降低頁面的響應速度，一些搜尋引擎可能因此對排名降級。客戶端/伺服器程式碼分割槽.增加伺服器與客戶端之間所共享程式碼量的一種方法是使用如、等無邏輯模板語言。這種模板可以用不同的託管語言來呈現，如伺服器上的Ruby和客戶端的JavaScript。但是，單純共享模板通常需要重複使用業務邏輯來選擇正確的模板，並使用資料填充它們。僅更新頁面的一小部分時，從模板呈現可能會產生負面的效能影響。替換整個模板也可能會干擾使用者的選擇或游標位置，只更新變更的值則可能不會。為避免這些問題，應用程式可以使用或粒度DOM操作來更新頁面的相應部分，而不是重新呈現整個模板。瀏覽器歷史記錄.根據單頁應用模型的定義，它只有“單個頁面”，因此這打破了瀏覽器為頁面歷史記錄導航所設計的“-{zh-cn:前進/後退;zh-tw:上一頁、下一頁}-”功能。當用戶按下後退按鈕時，可能會遇到可用性障礙，頁面可能-{返回}-真正的上一個頁面，而非使用者所期望的上一個頁面。傳統的解決方案是不斷更改瀏覽器網址的雜湊片段識別符號以保持與當前的螢幕狀態一致。這種方案可以透過JavaScript實現，並在瀏覽器中建立起網址歷史事件。只要單頁應用能根據網址雜湊所包含的資訊重新生成相同的螢幕狀態，就能實現預期的後退按鈕行為。而為進一步解決此問題，HTML5規範引入了pushState 來提供-{zh-cn:程式碼;zh-tw:程式碼}-對實際網址和瀏覽器歷史的訪問。分析.諸如Google分析等分析工具高度依賴在瀏覽器中載入全新的頁面，而單頁應用的工作方式不同於此。初次載入的速度.單頁應用的第一頁載入會比基於伺服器的-{zh-cn:應用;zh-tw:應用程式}-慢。這是因為首次載入必須先拿到框架和應用程式的程式碼，再在瀏覽器中呈現所需的檢視。基於伺服器的應用程式只需將所需的HTML推送到瀏覽器，從而減少了延遲和下載用時。加快頁面載入速度.有一些方法可以加快單頁應用的初次載入速度，比如採用多項快取措施、需要時再載入某些模組。但這依舊不可能擺脫需要下載框架的事實，某些部分必須在呈現前下載。這是一個“現在支付，或者稍後支付”的問題。效能與等待時間的權衡是開發者必須作出的權衡。頁面生命週期.單頁應用在初始頁面載入時被完全載入，然後頁面區域被替換或更新為按需從伺服器載入的新頁面片段。為避免過度下載未使用的功能，單頁應用通常會逐漸下載更多內容，如所需要的功能、頁面的一小塊，或者完整的一頁。單頁應用呈現技術類似。