本文內容涵蓋
- Web 應用程式生命週期
- 處理 HTML 以產生網頁
- JS 程式碼的執行順序
- 與事件互動
- 事件迴圈
Web 應用程式生命週期
Web 應用程式真正的生命起始於第四步驟:收到伺服器回傳的頁面時。
- 使用者:輸入網址或是點擊超連結
- 瀏覽器:產生請求並送往伺服器
- 伺服器:收到請求,執行動作或是取得資源,將回應送回客戶端
- 瀏覽器:收到回應頁面,解析 HTML、CSS、JavaScript 並渲染頁面 [頁面建立階段]
- 瀏覽器與使用者:[事件處理]
- 瀏覽器監看事件佇列
- 使用者與頁面元素互動
- 瀏覽器一次處理一個事件
- … 持續這個循環
- 使用者關閉 Web 應用程式
W eb 應用程式也是一種圖形使用者介面,所以和其他 GUI 應用程式一樣,都是先建立頁面,再進行事件處理直至被使用者關閉,就結束了生命週期。
頁面建立階段
設置使用者頁面。
事件處理階段
進入一個等待事件發生的迴圈,並啟用事件處理器。
生命週期結束
使用者關閉 Web 應用程式。
頁面建立階段 _ (4)
網頁在可以被操作或單純顯示之前,瀏覽器須先根據伺服器接收到的回應內容(HTML、CSS、JavaScript),此階段的目標是「設置 UI」,分為兩個步驟:
- 解析 HTML 並建立文件物件模型 DOM
- 執行 JavaScript 程式
瀏覽器處理 HTML 節點時執行「步驟 1」,每次只處理一個節點;
當遇到特殊類型 HTML 元素,即是包含/引用 JavaScript 的 <script>
,就執行「步驟 2」。
HTML 節點關係
父節點、子節點、兄弟節點。
瀏覽器能否永遠正確地根據 HTML 產生網頁
DOM 文件物件模型,其實 DOM 不等於 HTML,雖然 DOM 是由 HTML 建構,但 HTML 其實是 DOM 建構時所遵循的藍圖,若建構時發現錯誤,瀏覽器會容錯、修復它,如此才能夠建構「有效」的 DOM。
<head>
的設計意圖
用於提供一般性的頁面訊息,比如說:網頁標題、字元編碼、外部樣式、外部程式。
不是用來定義「頁面內容」(DOM)的,所以如果把非頁面訊息的元素,放進 <head>
,會被瀏覽器靜靜地修復,比如說 <p>
,就會被默默移動到 <body>
中。
頁面建立階段時,遇到特殊類型 HTML 元素 <script>
<script>
元素用來包含 JavaScript 程式碼。
而在這個情況之下,瀏覽器會暫停建立 DOM 結構,而先執行 JavaScript 程式碼。
瀏覽器的 JavaScript 引擎
<script>
中的程式碼,由瀏覽器的 JavaScript 引擎執行,提供頁面動態行為。
- Firefox:Spidermonkey
- Chrome:V8
- Opera:V8
- Edge(IE):Chakra
JavaScript 全域物件
瀏覽器中 JavaScript 引擎的全域物件是 window
物件,代表頁面所屬的「瀏覽器視窗」。
window
物件是特殊的全域物件,因為它可以存取:
- 所有其他的全域物件
- 全域變數(包含使用者自訂的全域變數)
- 瀏覽器 API
window
物件中,最重要的屬性是 document
,代表目前頁面的 DOM 結構,透過 document
物件,JavaScript 可以任意建立及插入、修改、刪除等所在頁面的 DOM 結構,但也有一些無法做到的事,比如選取和刪除尚未建立的元素。因為有時 JavaScript 程式碼還沒被讀取,故有些元素還沒透過 JavaScript 建立並插入到 DOM 中,所以有些開發者傾向將 <script>
放在頁面底部。
事件處理階段 _ (5)
頁面互動性
在頁面建立階段,除了修改 DOM 以外,還能註冊事件監聽器(Event Handler),監聽使用者的操作,當某些操作被觸發時,瀏覽器會針對不同類型的事件做出反應,也就是呼叫被定義好要觸發的函式(Callback)。透過這樣的流程,去增加頁面的互動性。
事件處理概述
- 瀏覽器執行環境的核心是「單一執行緒」,也就是一次只執行一段程式碼。
- 瀏覽器透過「事件佇列」追蹤已發生但尚未處理的事件,並且這些事件都會按照發生的順序放在同一個事件佇列中。
- 流程:
+---------+ 檢測 +------------------+ 是 +-----------+
| 瀏覽器 | => | 事件佇列頂部有事件?| => | 執行一個事件 |
+---------+ +------------------+ +-----------+
↑ 繼續檢測 ↓ 否
+-------------+
- 將事件放入事件佇列中這件事情,是瀏覽器的工作機制,並不在頁面建立和事件處理階段之中,所以判斷何時該執行、加入佇列的這個動作不在事件處理的執行緒中。
- 事件是「非同步」的。
- 絕大多數程式碼會被這些事件類型觸發:
- 瀏覽器事件:網頁處於已經載入或未載入的狀態
- 網路事件:Ajax 事件、Server 端事件
- 使用者事件:使用者點擊滑鼠
- 計時器事件
註冊事件處理器(Event-handler Registration)
-
兩種方式可以註冊
-
將函式只給特定屬性:一次只能指派一個事件處理器,下次註冊就會清空前次的內容。
window.onload = function () {}; document.body.onclick = function () {};
-
使用內建的 addEventlistener:針對同個元素,可以新增多個相同或不同的事件處理器。
window.addEventListener('load', function () {}); document.body.addEventListener('click', function () {});
-
簡易 QA
- 一個 Web 應用程式可以同時處理多少個事件?
- 一個。
- 為什麼瀏覽器必須使用事件佇列來處理多個事件?
- 因為需要追蹤已經發生但尚未處理的事件。
留言