忍者 2:Web 應用程式生命週期

本文內容涵蓋

  • Web 應用程式生命週期
  • 處理 HTML 以產生網頁
  • JS 程式碼的執行順序
  • 與事件互動
  • 事件迴圈

Web 應用程式生命週期

Web 應用程式真正的生命起始於第四步驟:收到伺服器回傳的頁面時。

  1. 使用者:輸入網址或是點擊超連結
  2. 瀏覽器:產生請求並送往伺服器
  3. 伺服器:收到請求,執行動作或是取得資源,將回應送回客戶端
  4. 瀏覽器:收到回應頁面,解析 HTML、CSS、JavaScript 並渲染頁面 [頁面建立階段]
  5. 瀏覽器與使用者:[事件處理]
    • 瀏覽器監看事件佇列
    • 使用者與頁面元素互動
    • 瀏覽器一次處理一個事件
    • … 持續這個循環
  6. 使用者關閉 Web 應用程式

W eb 應用程式也是一種圖形使用者介面,所以和其他 GUI 應用程式一樣,都是先建立頁面,再進行事件處理直至被使用者關閉,就結束了生命週期。

頁面建立階段

設置使用者頁面。

事件處理階段

進入一個等待事件發生的迴圈,並啟用事件處理器。

生命週期結束

使用者關閉 Web 應用程式。


頁面建立階段 _ (4)

網頁在可以被操作或單純顯示之前,瀏覽器須先根據伺服器接收到的回應內容(HTML、CSS、JavaScript),此階段的目標是「設置 UI」,分為兩個步驟:

  1. 解析 HTML 並建立文件物件模型 DOM
  2. 執行 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 物件是特殊的全域物件,因為它可以存取:

  1. 所有其他的全域物件
  2. 全域變數(包含使用者自訂的全域變數)
  3. 瀏覽器 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 應用程式可以同時處理多少個事件?
    • 一個。
  • 為什麼瀏覽器必須使用事件佇列來處理多個事件?
    • 因為需要追蹤已經發生但尚未處理的事件。
系統設計入門:效能與可擴展性的差異 RegExp 踩雷:Lookbehind Assertions

留言