深入瞭解新式網路瀏覽器 (第 4 部分)

Mariko Kosaka

輸入工具即將傳送至合成器

這是網誌系列文章的最後 4 部分,這是最後介紹 Chrome 的成果。並調查 程式碼顯示網站在前一篇文章中,我們介紹了轉譯程序,並瞭解合成器。這篇文章 ,瞭解合成器如何在使用者輸入內容時流暢地進行互動。

瀏覽器視角的輸入事件

聽到「輸入事件」時您可能只想到文字方塊或點擊滑鼠中的字 瀏覽器的視角;輸入是指使用者做出的任何手勢。將滑鼠滾輪的捲動設為輸入項目 也會視為輸入事件。

當使用者以手勢 (例如輕觸螢幕) 出現時,瀏覽器程序就是接收 手勢。不過,瀏覽器程序只能知道手勢於何處執行 分頁中的內容會由轉譯器程序處理因此瀏覽器程序會將事件 類型 (例如 touchstart) 及其座標至轉譯器程序。轉譯器程序會處理 正確事件事件。

輸入事件
圖 1:透過瀏覽器程序轉送至轉譯器程序的輸入事件

合成器收到輸入事件

圖 2:懸停在頁面圖層上的可視區域

在前一篇文章中,我們探討合成器如何透過合成過程順暢地處理捲動作業 光柵化層如果網頁未附加任何輸入事件監聽器,合成器執行緒可以 會建立新的複合式頁框,完全獨立於主執行緒。但如果某些事件 是否與網頁附加了監聽器?合成器執行緒如何得知事件需求 資料處理?

瞭解無法快速捲動的區域

由於執行 JavaScript 是主執行緒的工作,因此網頁合成時,合成器執行緒 標示在網頁上的區域,將事件處理常式附加為「Non-Fast Scrollable Region」。變更者: 只要有這項資訊,合成器執行緒就能確保將輸入事件傳送至主執行緒 指定事件的發生時間如果輸入事件來自這個區域之外, 合成器執行緒會承載新影格,而無需等待主執行緒。

有限的非快速捲動區域
圖 3:說明無法快速捲動區域的輸入圖表

編寫事件處理常式時請注意這一點

事件委派是網頁開發中的常見事件處理模式。既然如此 可以在最頂端的元素附加一個事件處理常式,並根據事件目標委派工作。個人中心 您可能看過或編寫類似下方的程式碼。

document.body.addEventListener('touchstart', event => {
    if (event.target === area) {
        event.preventDefault();
    }
});

由於您只需要為所有元素編寫一個事件處理常式,因此這個事件的人體工學 而且委派模式很有吸引力不過,如果您是透過瀏覽器的時間點查看這個程式碼 檢視畫面,現在整個網頁會標示為不可快速捲動的區域。也就是說 相較於網頁中特定部分的輸入內容,合成器執行緒必須 與主執行緒通訊,並在每次輸入事件發生時等待該執行緒。因此, 揭開合成器的流暢捲動功能。

整頁無法快速捲動的區域
圖 4:關於無法快速捲動區域涵蓋整個頁面的輸入圖表

如要避免這種情況發生,您可以在事件中傳遞 passive: true 個選項 接聽程式。您仍想讓瀏覽器監聽主執行緒中的事件。 但合成器也可以繼續建構新的影格

document.body.addEventListener('touchstart', event => {
    if (event.target === area) {
        event.preventDefault()
    }
 }, {passive: true});

確認活動是否可取消

頁面捲動
圖 5:網頁中部分固定為水平捲動的網頁

假設網頁中有一個方塊,規定捲動方向範圍僅限水平捲動。

在指標事件中使用 passive: true 選項表示頁面捲動可以順暢運作, 垂直捲動的啟動時間可能在您希望preventDefault的時候才開始,這樣才能 可以往反方向移動您可以使用 event.cancelable 方法檢查此狀態。

document.body.addEventListener('pointermove', event => {
    if (event.cancelable) {
        event.preventDefault(); // block the native scroll
        /*
        *  do what you want the application to do here
        */
    }
}, {passive: true});

或者,您也可以使用 CSS 規則 (例如 touch-action),徹底刪除事件處理常式。

#area {
  touch-action: pan-x;
}

尋找事件目標

點擊測試
圖 6:查看繪製記錄的主執行緒詢問 x.y 點上繪製的內容

當合成器執行緒將輸入事件傳送至主要執行緒時,首先要執行的就是命中 測試以找出事件目標。命中測試會使用算繪期間產生的繪製記錄資料 程序,找出事件發生時的點座標底下。

盡量減少將事件分派到主要執行緒

在前一篇文章中,我們提到了一般螢幕每秒重新整理 60 次畫面 我們要如何跟上節奏,讓動畫更流暢一般觸控螢幕 裝置每秒可傳送 60 至 120 次觸控事件,一般滑鼠傳送事件數為 第二。輸入事件的保真度高於畫面重新整理的保真度。

如果 touchmove 等連續事件每秒傳送至主執行緒 120 次, 可能觸發過多命中測試和 JavaScript 執行速度 (與 螢幕可以重新整理。

未篩選的事件
圖 7:因影格時間軸淹水的事件造成頁面卡頓

為了盡量減少主執行緒呼叫的次數過多,Chrome 會合併連續事件 (例如 wheelmousewheelmousemovepointermovetouchmove) 且延遲派至 就在下一個 requestAnimationFrame 之前

聯合事件
圖 8:與之前相同的時間軸,但事件經過彙整和延遲

任何離散事件,例如 keydownkeyupmouseupmousedowntouchstarttouchend 工作,

使用 getCoalescedEvents 取得影格內事件

對大部分的網頁應用程式來說,聯合事件應足以提供良好的使用者體驗。 不過,若您正在建構應用程式 touchmove 座標時,座標之間可能會遺失,導致繪製平滑的線條。在此情況下 您可以在指標事件中使用 getCoalescedEvents 方法,取得這些 並產生聯合事件。

getCoalescedEvents
圖 9:平滑的觸控手勢路徑,左側為合併受限的路徑
window.addEventListener('pointermove', event => {
    const events = event.getCoalescedEvents();
    for (let event of events) {
        const x = event.pageX;
        const y = event.pageY;
        // draw a line using x and y coordinates.
    }
});

後續步驟

本系列文章已說明網路瀏覽器的內部運作方式。如果從未想過 開發人員工具建議在事件處理常式中加入 {passive: true},或是撰寫 async 的原因 屬性加入指令碼,希望本系列介紹為什麼瀏覽器需要這些屬性 資訊,提供更迅速流暢的網路體驗。

使用 Lighthouse

如果您想製作適合瀏覽器的程式碼,但不知道從何著手, Lighthouse 這項工具能執行任何網站的稽核,並給予一個 說明哪些地方做得不錯,以及哪些部分需要改善。詳閱稽核清單 也能讓您瞭解瀏覽器重視哪些事情。

瞭解如何評估成效

成效調整可能因網站而異,因此務必評估成效 並決定最適合您網站的方式Chrome 開發人員工具團隊提供了一些教學課程 評估網站成效的方法

為網站新增功能政策

如要採取額外步驟,我們推出了新的功能政策 網路平台功能。這類功能是您在建構專案時派上用場的輔助機制。啟用中 功能政策可以保證應用程式的特定行為,避免出錯。 舉例來說,如要確保應用程式一律不會封鎖剖析作業,您可以 同步指令碼政策。啟用 sync-script: 'none' 後,會受限於剖析器的 JavaScript 就無法執行這可避免任何程式碼封鎖剖析器,以及 也不用擔心暫停剖析器的問題

總結

謝謝

開始架設網站時,我幾乎只關心程式碼撰寫方式, 提升工作效率。這些事項很重要,但我們也應該思考 套用我們撰寫的程式碼新世代瀏覽器不斷向心力, 讓使用者享有更優質的網路體驗。妥善整理程式碼,善待瀏覽器 進而改善使用者體驗。誠摯希望您和我一起努力,為瀏覽器提供協助!

非常感謝大家看過這系列影片初期草稿 (包括但不限於) ):Alex RussellPaul IrelandMegin KearneyEric Bidelman Mathias BynensAddy OsmaniKinuko YasudaNasko Oskov、 和 Charlie Reis

你喜歡這個系列叢書嗎?如果你對日後貼文有任何疑問或建議, 請在下方留言區或 @kosamari 提供你的回覆。 。