現代Web應用程序也稱為單頁應用程序。這是什麼意思?
過去,當瀏覽器的功能遠不如今天,並且JavaScript性能很差時,每個頁面都來自服務器。每次您單擊某些內容時,都會向服務器發出新請求,然後瀏覽器隨後會加載新頁面。
只有極富創新性的產品才能發揮不同的作用,並嘗試新方法。
如今,在諸如React之類的現代前端JavaScript框架中流行的應用程序通常是作為單頁應用程序構建的:您只需加載應用程序代碼(HTML,CSS,JavaScript)一次,當您與應用程序進行交互時,通常會發生JavaScript攔截瀏覽器事件的情況,而不是向服務器發出新請求,然後服務器返回一個新文檔,而是由客戶端請求一些JSON或在服務器上執行操作但是用戶看到的頁面永遠不會被完全抹掉,其行為更像是桌面應用程序。
單頁應用程序內置於JavaScript中(或至少已編譯成JavaScript),並且可以在瀏覽器中工作。
技術始終是相同的,但是應用程序的工作原理和一些關鍵組成部分是不同的。
單頁應用程序示例
一些著名的例子:
- 郵箱
- 谷歌地圖
- 推特
- Google雲端硬碟
SPA的優缺點
SPA對用戶的感覺要快得多,因為您現在可以立即獲得反饋,而不必等待客戶端與服務器之間的通信發生,而不必等待瀏覽器重新呈現頁面。這是應用程序製造商的責任,但是您可以擁有過渡和微調器以及任何類型的UX改進,這些改進肯定比傳統工作流程更好。
除了使用戶體驗更快之外,服務器還將消耗更少的資源,因為您可以專注於提供有效的API,而不是在服務器端構建佈局。
如果您還基於API構建移動應用程序,那麼這將是理想的選擇,因為您可以完全重用現有的服務器端代碼。
單頁應用程序很容易轉換為漸進式Web應用程序,從而使您能夠提供本地緩存並支持服務的脫機體驗(如果用戶需要在線,則可以提供更好的錯誤消息)。
當不需要SEO(搜索引擎優化)時,SPA最好使用。例如,對於在登錄後起作用的應用程序。
搜索引擎雖然每天都在進步,但仍然難以為使用SPA方法而非傳統的服務器呈現頁面建立的站點建立索引。博客就是這種情況。如果您要依賴搜索引擎,那麼即使沒有服務器也不能創建一部分應用程序,也不必擔心創建單個頁面應用程序。
在編寫SPA時,您將編寫大量JavaScript。由於該應用程序可以長時間運行,因此您將需要更多地註意可能的內存洩漏-如果過去您的頁面的生命週期以分鐘為單位計算,那麼現在SPA可能會在數小時內保持打開狀態數小時。時間以及是否存在任何內存問題,這將使瀏覽器的內存使用量增加更多,而且如果您不加以注意,它將導致令人不快的緩慢體驗。
團隊合作時,SPA非常有用。後端開發人員可以只專注於API,前端開發人員可以專注於利用後端內置的API來創造最佳的用戶體驗。
缺點是,單頁應用程序嚴重依賴JavaScript。這可能會使在低功率設備上運行的應用程序在速度方面的體驗較差。另外,您的某些訪問者可能只是禁用了JavaScript,並且您還需要考慮所構建內容的可訪問性。
覆蓋導航
由於您擺脫了默認的瀏覽器導航,因此必須手動管理URL。
應用程序的這一部分稱為路由器。一些框架已經為您做好了準備(例如Ember),其他框架則需要可以完成此工作的庫(例如反應路由器)。
有什麼問題?最初,這是開發人員構建單頁應用程序的一種後繼想法。這導致了常見的“後退按鈕”問題:在應用程序內部導航時,URL保持不變(由於瀏覽器默認導航被劫持),然後按了後退按鈕,這是用戶執行的常見操作,可轉到上一個屏幕,可能會轉到您很久以前訪問過的網站。
現在可以使用歷史API由瀏覽器提供,但是大多數時候您會使用內部使用該API的庫,例如反應路由器。
免費下載我的JavaScript初學者手冊
更多js教程:
- JavaScript中應避免的事情(不良部分)
- JavaScript中的延遲和承諾(+ Ember.js示例)
- 如何使用JavaScript將文件上傳到服務器
- JavaScript編碼風格
- JavaScript數組簡介
- JavaScript編程語言簡介
- 完整的ECMAScript 2015-2019指南
- 了解JavaScript承諾
- JavaScript的詞彙結構
- JavaScript類型
- JavaScript變數
- 示例Web應用程序提示列表
- JavaScript函數式編程簡介
- 具有Async和Await的現代異步JavaScript
- JavaScript循環和範圍
- Map JavaScript數據結構
- 設置JavaScript數據結構
- JavaScript模板文字指南
- 學習JavaScript的路線圖
- JavaScript表達式
- 發現JavaScript計時器
- JavaScript事件說明
- JavaScript循環
- 使用map,filter,reduce和find編寫JavaScript循環
- JavaScript事件循環
- JavaScript函數
- JavaScript詞彙表
- JavaScript閉包說明
- JavaScript Arrow函數教程
- JavaScript正則表達式指南
- 如何在JavaScript中檢查字符串是否包含子字符串
- 如何從JavaScript中的數組中刪除項目
- 如何深度克隆JavaScript對象
- Introduction to Unicode and UTF-8
- JavaScript中的Unicode
- 如何在JavaScript中大寫字符串的第一個字母
- 如何在JavaScript中將數字格式化為貨幣值
- 如何在JavaScript中將字符串轉換為數字
- 這在JavaScript中
- 如何在JavaScript中獲取當前時間戳
- JavaScript嚴格模式
- JavaScript立即調用函數表達式(IIFE)
- 如何使用JavaScript重定向到另一個網頁
- 如何從JavaScript對像中刪除屬性
- 如何在JavaScript中將項目追加到數組
- 如何檢查JavaScript對象屬性是否未定義
- ES模塊簡介
- CommonJS簡介
- JavaScript異步編程和回調
- 如何替換JavaScript中所有出現的字符串
- 現代JavaScript語法快速參考指南
- 如何在JavaScript中修剪數字中的前導零
- 如何檢查JavaScript對象
- 關於JavaScript日期的權威指南
- Moment.js教程
- JavaScript中的分號
- JavaScript算術運算符
- JavaScript Math對象
- 在JavaScript中生成隨機且唯一的字符串
- 如何使您的JavaScript函數進入睡眠狀態
- JavaScript原型繼承
- JavaScript例外
- 如何使用JavaScript類
- JavaScript食譜
- JavaScript中的引號
- 如何在JavaScript中驗證電子郵件地址
- 如何獲取JavaScript數組中一組對象的唯一屬性
- 如何在JavaScript中檢查字符串是否以另一個字符串開頭
- 如何在JavaScript中創建多行字符串
- ES6指南
- 如何在JavaScript中獲取當前URL
- ES2016指南
- 如何使用JavaScript中的值初始化新數組
- ES2017指南
- ES2018指南
- 如何在Array.prototype.map()中使用Async和Await
- 異步與同步代碼
- 如何在JavaScript中生成兩個數字之間的隨機數
- HTML Canvas API教程
- 如何在JavaScript中的for-of循環中獲取迭代的索引
- 什麼是單頁應用程序?
- WebAssembly簡介
- JSON簡介
- JSONP指南
- Should you use or learn jQuery in 2020?
- 如何使用純JavaScript隱藏DOM元素
- 如何在JavaScript中合併兩個對象
- 如何清空JavaScript數組
- 如何使用JavaScript編碼URL
- 如何在JavaScript中設置默認參數值
- 如何在JavaScript中按屬性值對對像數組進行排序
- 如何計算JavaScript對像中的屬性數量
- JavaScript中的call()和apply()
- WebRTC庫PeerJS簡介
- 使用Rest和Spread處理對象和數組
- 用JavaScript分解對象和數組
- 調試JavaScript的權威指南
- TypeScript指南
- 在JavaScript中動態選擇對象的方法
- 將undefined傳遞給JavaScript立即調用的函數表達式
- 鬆散類型與強類型語言
- 如何使用JavaScript設置DOM元素的樣式
- 用JavaScript投放
- JavaScript生成器教程
- node_modules文件夾的大小不是問題。這是一種特權
- 在JavaScript中導入模塊時如何解決意外的標識符錯誤
- 如何在JavaScript中列出對象的所有方法
- 字符串replace()方法
- 字符串search()方法
- 我如何運行一些JavaScript代碼段
- ES2019指南
- 字符串charAt()方法
- 字符串charCodeAt()方法
- 字符串codePointAt()方法
- 字符串concat()方法
- 字符串endsWith()方法
- 字符串include()方法
- 字符串indexOf()方法
- 字符串lastIndexOf()方法
- 字符串localeCompare()方法
- 字符串match()方法
- 字符串normalize()方法
- 字符串padEnd()方法
- 字符串padStart()方法
- 字符串repeat()方法
- 字符串slice()方法
- 字符串split()方法
- 字符串startsWith()方法
- String substring()方法
- 字符串toLocaleLowerCase()方法
- 字符串toLocaleUpperCase()方法
- String toLowerCase()方法
- 字符串toString()方法
- String toUpperCase()方法
- 字符串trim()方法
- String trimEnd()方法
- String trimStart()方法
- JavaScript的記憶化
- 字符串valueOf()方法
- JavaScript參考:字符串
- Number isInteger()方法
- Number isNaN()方法
- Number isSafeInteger()方法
- Number parseFloat()方法
- Number parseInt()方法
- Number toString()方法
- Number valueOf()方法
- Number toPrecision()方法
- Number toExponential()方法
- Number toLocaleString()方法
- Number toFixed()方法
- Number isFinite()方法
- JavaScript參考:編號
- JavaScript屬性描述符
- 對象的assign()方法
- 對象的create()方法
- Object defineProperties()方法
- Object defineProperty()方法
- 對象entry()方法
- 對象Frozen()方法
- Object getOwnPropertyDescriptor()方法
- Object getOwnPropertyDescriptors()方法
- Object getOwnPropertyNames()方法
- Object getOwnPropertySymbols()方法
- Object getPrototypeOf()方法
- Object is()方法
- Object isExtensible()方法
- Object isFrozen()方法
- Object isSealed()方法
- 對象keys()方法
- 對象的preventExtensions()方法
- 對象seal()方法
- Object setPrototypeOf()方法
- Object values()方法
- 對象的hasOwnProperty()方法
- Object isPrototypeOf()方法
- 對象的propertyIsEnumerable()方法
- Object toLocaleString()方法
- Object toString()方法
- Object valueOf()方法
- JavaScript參考:對象
- JavaScript賦值運算符
- JavaScript國際化
- JavaScript typeof運算子
- JavaScript新運算符
- JavaScript比較運算符
- JavaScript運算符優先級規則
- JavaScript instanceof運算符
- JavaScript陳述式
- JavaScript範圍
- JavaScript類型轉換(廣播)
- JavaScript相等運算符
- JavaScript if / else條件
- JavaScript切換條件
- JavaScript刪除運算符
- JavaScript函數參數
- JavaScript Spread運算符
- JavaScript返回值
- JavaScript邏輯運算符
- JavaScript三元運算符
- JavaScript遞歸
- JavaScript對象屬性
- JavaScript錯誤對象
- JavaScript全局對象
- JavaScript filter()函數
- JavaScript map()函數
- JavaScript reduce()函數
- JavaScript`in`運算子
- JavaScript運算子
- 如何在JavaScript中獲取CSS屬性的值
- 如何將事件偵聽器添加到JavaScript中的多個元素
- JavaScript私有類字段
- 如何在JavaScript中按日期值對數組排序
- JavaScript公共類字段
- JavaScript符號
- 如何使用JavaScript bcrypt庫
- 使用對象解構時如何重命名字段
- 如何在不使用TypeScript的情況下檢查JavaScript中的類型
- 如何檢查JavaScript數組是否包含特定值
- 雙重否定運算符是什麼!用JavaScript做嗎?
- JavaScript比較中應使用哪個等號運算符? == vs ===
- JavaScript仍然值得學習嗎?
- 如何在JavaScript中返回異步函數的結果
- 如何在JavaScript中檢查對像是否為空
- 如何突破JavaScript中的for循環
- 如何在JavaScript中的特定索引處將項目添加到數組
- 為什麼不應該修改JavaScript對象原型
- 在JavaScript中使用let和var有什麼區別?
- 用於激活JavaScript功能的鏈接
- 如何在JavaScript中連接兩個字符串
- 如何在JavaScript中連接兩個數組
- 如何檢查JavaScript值是否為數組?
- 如何在JavaScript中獲取數組的最後一個元素?
- 如何使用Axios發送urlencoded數據
- 如何使用JavaScript獲取明天的日期
- 如何使用JavaScript獲取昨天的日期
- 如何從JavaScript日期獲取月份名稱
- 如何檢查兩個日期是否在JavaScript中是同一天
- 如何在JavaScript中檢查日期是否指向過去的一天
- 標有JavaScript的語句
- 如何等待2個或更多的Promise在JavaScript中解析
- 如何在JavaScript中獲取兩個日期之間的日期
- 如何使用提取上傳文件
- 如何在JavaScript中格式化日期
- 如何遍歷JavaScript中的對象屬性
- 如何在JavaScript中計算兩個日期之間的天數
- 如何在ES模塊中使用頂級等待
- JavaScript動態導入
- JavaScript可選鏈接
- 如何在JavaScript中替換字符串內的空格
- JavaScript空合併
- 如何在JavaScript中展平數組
- JavaScript的十年
- 如何使用Axios發送授權標頭
- JavaScript中的關鍵字和保留字列表
- 如何在JavaScript中將數組轉換為字符串
- 如何刪除所有的node_modules文件夾內容
- 如何從JavaScript數組中刪除重複項
- 在JavaScript中讓vs const
- 各種JavaScript庫中的相同POST API調用
- 如何在JS中獲取數組中的前n個項目
- 如何在JS中將數組劃分為多個相等的部分
- 如何減慢JavaScript中的循環
- 如何在HTML畫布中加載圖像
- 如何在JavaScript中將字符串切成單詞
- 如何在JavaScript中將數組分成兩半
- 如何將文本寫入HTML畫布
- 如何在JavaScript中刪除字符串的最後一個字符
- 如何在JavaScript中刪除字符串的第一個字符
- 如何修復TypeError:無法分配為只讀對象“#< Object>”的屬性“ exports”錯誤
- 如何創建退出意圖彈出窗口
- 如何檢查一個元素是否是另一個元素的後代
- 如何對每個Axios請求強制使用憑據
- 如何解決JavaScript中的“不是函數”錯誤
- 蓋茨比,如何更改圖標
- 使用Gatsby加載外部JS文件
- 如何使用JavaScript檢測暗模式
- 包裹,如何修復“ regeneratorRuntime未定義”錯誤
- 如何檢測Adblocker是否與JavaScript一起使用
- 使用TypeScript中的類型進行對象分解
- Deno手冊:Deno的簡要介紹🦕
- 如何使用JavaScript獲取路徑或URL的最後一段
- 如何隨機播放JavaScript數組中的元素
- 如何檢查JavaScript對像中是否存在密鑰
- 事件冒泡和事件捕獲
- event.stopPropagation與event.preventDefault()與在DOM事件中返回false
- JavaScript中的原始類型與對象
- 在JavaScript中,如何判斷值的類型?
- 如何從JavaScript中的函數返回多個值
- JavaScript中的箭頭函數與常規函數
- 我們可以通過哪些方式訪問對象屬性的值?
- JavaScript中的null和undefined有什麼區別?
- 方法和函數有什麼區別?
- 我們可以通過哪些方法擺脫JavaScript循環?
- JavaScript for..of循環
- 什麼是JavaScript中的對象解構?
- JavaScript吊起了什麼?
- 如何使用JavaScript將逗號更改為點
- 使用DOM時計時的重要性
- 如何反轉JavaScript數組
- 如何在JavaScript中檢查值是否為數字
- 如何在JavaScript函數中接受無限的參數
- JavaScript代理對象
- 使用香草JavaScript在瀏覽器中進行事件委託
- JavaScript super關鍵字
- XState簡介
- 值是通過引用傳遞還是通過JavaScript中的值傳遞?
- JavaScript中的自定義事件
- JavaScript中的自定義錯誤
- JavaScript中的命名空間
- JavaScript中逗號的奇怪用法
- JavaScript中的鏈接方法調用
- 如何處理承諾拒絕
- 如何在JavaScript中交換兩個數組元素
- 如何在使用Gitbook時解決“ cb.apply不是函數”錯誤
- 如何在JavaScript中的數組開頭添加項目
- Gatsby,修復“找不到模塊gatsby-cli / lib / reporter”錯誤
- 如何獲取JavaScript數組中項目的索引
- 如何在JavaScript中測試空對象
- 如何將對象解構為JavaScript中的現有變量
- 數組JavaScript數據結構
- 堆棧JavaScript數據結構
- JavaScript數據結構:隊列
- JavaScript數據結構:集
- JavaScript數據結構:字典
- JavaScript數據結構:鏈接列表
- JavaScript,如何導出函數
- JavaScript,如何導出多個功能
- JavaScript,如何退出功能
- JavaScript,如何在字符串中查找字符
- JavaScript,如何過濾數組
- JavaScript,如何擴展類
- JavaScript,如何在數組中查找重複項
- JavaScript,如何替換數組的項
- JavaScript算法:線性搜索
- JavaScript算法:二進制搜索
- JavaScript算法:選擇排序
- JavaScript算法:Quicksort
- JavaScript算法:合併排序
- JavaScript算法:冒泡排序