INP 優化拆解——三段延遲與 Long Task 提速步驟

大多數人以為「網站速度」就是頁面載入得快不快,但 Google 真正盯著看的,是你載入完之後那段時間。Chrome 的使用資料顯示,使用者待在一個頁面上的時間,有九成是發生在載入完成之後——也就是他開始點按鈕、滑選單、打字填表單的那段。偏偏這段最被忽略:在高流量網站裡,每兩個就有一個沒能通過 INP 這項指標,反觀一般網站的行動版過關率還有近八成,落差就卡在「互動順不順」這件小事上。

問題是,當你點下按鈕、畫面卻慢半拍才有反應,你不會覺得「網路慢」,你會覺得這網站壞了,然後關掉。INP(Interaction to Next Paint,與下一個畫面繪製的互動延遲)量的就是這件事——從你動作開始,到瀏覽器把回饋畫到螢幕上的那段延遲。 自從 2024 年 3 月它取代 FID 成為 Core Web Vitals 的正式成員,互動順暢度就直接掛進了搜尋排名的考量裡。

好消息是,INP 不像玄學,它可以被拆解、被量測、被一段一段修。先從它到底在量什麼講起,再把它拆成三段延遲,看清楚 Long Task 怎麼拖垮你的分數,最後一步步把卡點清掉。

INP 是什麼?它跟 FID 有什麼差異

INP 是一個衡量「網頁對使用者互動回應有多快」的指標。它會觀察使用者整趟造訪裡,所有的點擊、輕觸和鍵盤輸入各自花了多久才得到畫面回饋,最後回報其中接近最差的那一次當作這頁的 INP 值。換句話說,它量的不是某一次互動,而是整頁互動體驗的可靠程度。

那它跟前一代的 FID(First Input Delay,首次輸入延遲)差在哪?關鍵的不同有三個:

  • 量的次數不同:FID 只測「第一次」互動的延遲,INP 測整個生命週期裡的「所有」互動。
  • 量的範圍不同:FID 只算到瀏覽器開始處理為止,INP 一路算到下一個畫面真正畫出來。
  • 可靠度不同:第一次互動往往不是最慢的那次,FID 容易報喜不報憂;INP 抓的是接近最差的互動,更貼近真實感受。

簡單說,FID 像是只看你進門那一刻的第一印象,INP 則是把你逛完整間店的每個卡頓都記下來。這也是 Google 換掉它的原因——使用者九成時間都花在載入後,只看第一次互動實在說不清楚整頁好不好用。

要特別提一句:INP 只看三種互動,分別是滑鼠點擊、觸控螢幕的輕觸、實體或螢幕鍵盤的按鍵。滑鼠懸停(hover)和單純的捲動(scrolling)不算在內。所以你拼命優化捲動動畫,對 INP 分數本身是沒幫助的——除非那個捲動監聽器順手把主執行緒卡住了,那又是另一回事。

INP 多少才算及格?綠色、橘色、紅色的分界

先給結論,INP 的及格線是 200 毫秒,這個值要看實際使用者資料的第 75 百分位數,並且行動版和桌機版分開算。Google 用三個顏色把回應速度分成三段:

  • 綠色(良好):INP 小於或等於 200 毫秒,代表頁面對絕大多數互動都能快速回應。
  • 橘色(需要改善):INP 介於 200 到 500 毫秒之間,使用者開始感覺得到延遲。
  • 紅色(不佳):INP 大於 500 毫秒,互動明顯卡頓,體驗已經受損。

為什麼是看第 75 百分位數,而不是平均?因為平均會被少數很快的互動稀釋掉,第 75 百分位數的意思是「至少四分之三的使用者體驗有這麼好或更好」,這比平均誠實得多。同樣的道理,當一頁互動次數很多時,INP 會忽略每 50 次裡最慢的那一次,避免某次隨機的卡頓被當成常態。

這條線看起來嚴格,但實際分布很兩極。行動版整體大約有近八成的頁面落在綠色區,桌機版更高、九成以上都過關;可是把範圍縮到全球最高流量的前一千個網站,過得了 INP 的卻只剩約一半。越大、越複雜、塞越多第三方腳本的網站,越容易在這裡失分——這也說明 INP 不是「小網站才要擔心」的指標,反而是功能堆得越多越該盯。

光知道及格線還不夠,要修就得先知道延遲是卡在哪一段。

INP 的三段延遲是哪三段?輸入、處理、呈現各卡在哪

每一次互動的延遲,其實是三段時間加起來的總和。這三段分別是輸入延遲(input delay)、處理時間(processing duration)、呈現延遲(presentation delay)。 要優化 INP,第一步永遠是先搞清楚自己慢在哪一段,再對症下藥,而不是一股腦把所有招式都用上。

我們一段一段看清楚它們各自代表什麼、又卡在哪:

  1. 輸入延遲:從你動作的那一刻起,到瀏覽器能開始執行對應的事件處理程式(event handler)為止的這段空窗。它之所以發生,多半是因為主執行緒當下正忙著跑別的工作,你的點擊只能排隊等。這也是 Long Task 最直接傷害的一段。
  2. 處理時間:瀏覽器開始執行所有相關的事件回呼(callback),把該算的算完、該改的狀態改完所花的時間。事件處理程式裡的 JavaScript 越肥、DOM 操作越複雜、夾帶的同步運算越重,這段就拖越久。
  3. 呈現延遲:回呼都跑完之後,瀏覽器把更新後的畫面真正繪製到螢幕上的那段時間。版面如果要重新計算的範圍很大、或要重繪的元素很多,這段就會變長。

三段加起來,才是使用者實際感受到的那一下延遲。這個拆法的價值在於,它把「網站好慢」這種模糊抱怨,變成三個可以分別下手的具體目標。在實務上,輸入延遲和處理時間通常是大頭,而它們背後最常見的共同元凶,就是下一段要講的 Long Task。

Long Task 是什麼?為什麼它是 INP 的頭號元兇

Long Task 指的是任何在主執行緒上跑超過 50 毫秒的工作。要理解它為什麼致命,得先認識主執行緒這個角色。

主執行緒是瀏覽器裡負責跑絕大多數事情的那條線——解析 HTML、計算 CSS、執行你寫的 JavaScript,幾乎都擠在這一條上。而它有個硬限制,一次只能做一件事。當一件工作占著主執行緒不放,所有後來的事情,包括使用者剛剛點下去的那個按鈕,都只能排在後面乾等。

50 毫秒這條線是這樣畫出來的——只要一件工作超過 50 毫秒,超出的部分就被算成它的「阻塞時間(blocking time)」,這段時間瀏覽器完全沒辦法回應任何互動。一兩個短工作你感覺不到,但一旦頁面上塞滿 Long Task,主執行緒長期被占用,你點什麼都慢半拍,介面就「凍」住了。

最容易踩的坑,是工程上看起來很乾淨、執行起來卻是一整塊的程式碼。舉個示意的例子,假設有個函式在使用者點「儲存」時被觸發:

  • 它依序呼叫了「驗證表單、顯示載入動畫、寫進資料庫、更新畫面、送出分析數據」這五件事。
  • 從程式架構看,拆成五個函式分工清楚、好維護。
  • 但瀏覽器不在乎你怎麼分函式——它把這五件事當成「一件工作」連續跑完。
  • 只要其中任何一件稍微吃重,整塊就輕鬆超過 50 毫秒,變成一個 Long Task。

結果就是,使用者點了「儲存」,得等這一整塊跑完瀏覽器才有空把回饋畫出來,INP 自然難看。問題不在你寫了幾個函式,而在它們被綁成一個無法中斷的大塊。知道病根在這,解法的方向也就清楚了——把大塊切開,讓瀏覽器有空檔回頭照顧使用者。

怎麼一步步降低 Long Task、把 INP 修回綠色

降低 INP 沒有單一神招,但有一條可操作的順序。核心思路只有一句:把長工作切小、把不急的工作往後讓,騰出主執行緒去回應使用者。以下是可以照著走的步驟。

步驟 1:先用真實使用者資料找出慢在哪一頁、哪個互動

優化第一步不是改 code,是先找對目標。你需要的是真實環境的現場資料(field data),因為 INP 是整趟造訪累積出來的,實驗室裡跑一次未必重現得了使用者實際遇到的卡頓。

  • 如果網站流量夠、符合 CrUX(Chrome 使用者體驗報告)收錄資格,直接打開 PageSpeed Insights 就能看到 INP 的現場數值。
  • 想要更細的情境資料,可以導入 Google 的 web-vitals JavaScript 套件,用 onINP 把每次互動的延遲、發生在哪個元素、屬於哪一段延遲都記錄下來。
  • 流量太少、CrUX 沒收錄的新站,現場資料會是空的,這時只能退而求其次用實驗室工具搭配總阻塞時間(TBT)當參考替代值。

先拿到「是哪一頁、哪個互動慢」這個答案,後面的力氣才不會白花。

步驟 2:在開發者工具裡重現那個慢互動,找出兇手 Long Task

鎖定問題頁之後,打開 Chrome DevTools 的效能(Performance)面板,照著使用者的操作流程把那個慢互動錄下來。重點是「在頁面剛載入、主執行緒最忙的時候」去操作,那是最容易抓到問題的時機。

錄完之後,在時間軸上找那些被標成 Long Task 的紅色區塊,看它對應到哪一段函式。你要確認的是:這次互動的延遲,主要卡在輸入延遲、處理時間,還是呈現延遲?卡在哪一段,下一步就往哪一段下手,而不是三段亂槍打鳥。

步驟 3:把不急、使用者看不到的工作往後讓

找到那塊肥工作後,第一個動作是分流。把「使用者馬上要看到回饋」的工作留在最前面先跑,把「跑不跑得完使用者當下都看不出來」的工作往後挪到另一個工作裡。

以前面那個「儲存」的例子來說,驗證表單、顯示載入動畫、更新畫面這幾件是使用者看得到的,要先做;寫進資料庫、送出分析數據這兩件,使用者當下看不出差別,就可以延後。最簡單的延後手法是用 setTimeout,把那段程式碼丟進一個之後才執行的工作,瀏覽器就有機會先把回饋畫出來。

不過 setTimeout 有個老問題,它讓出去之後,續做的工作會被排到佇列的「最後面」,萬一這時別人的腳本插了一堆工作進來,你的後半段就得排在它們後面,可能拖很久才輪到。

步驟 4:用 scheduler.yield() 把長工作切段,又不被別人插隊

如果一塊工作沒辦法簡單分成「前後兩半」,而是一個跑很多次的迴圈(例如要處理一大批資料),那就需要在中途「讓步」給主執行緒——做一段、放手讓瀏覽器喘口氣去回應互動、再回來接著做。

這裡推薦用 scheduler.yield()。它是專門為這件事設計的 API,你在 async 函式裡 await scheduler.yield(),函式就會在那一刻暫停、把主執行緒讓出去,等瀏覽器處理完手邊的高優先工作,再回來執行剩下的部分。它最大的好處,是讓出去之後續做的工作會被「優先」排回來執行,排在其他同類新工作的前面。這正是它贏過 setTimeout 的地方——setTimeout 是排到最後面,scheduler.yield() 是插回前面,所以你不會因為主動讓步反而被別人的腳本卡住。

要注意它目前主要是 Chromium 系瀏覽器支援,其他瀏覽器需要備援方案。常見做法是做功能偵測,有 scheduler.yield() 就用,沒有就退回用 Promise 包一層 setTimeout 來讓步。雖然備援方案拿不到「優先續做」的好處,但至少能讓瀏覽器保持回應。也可以直接引入 scheduler-polyfill,讓不同瀏覽器的行為盡量一致。

步驟 5:別切過頭,用 50 毫秒當批次門檻

切工作不是切越碎越好。scheduler.yield() 雖然快,但每讓一次、回來一次都有一點額外開銷。如果你在一個迴圈裡每跑一小步就讓一次,光是讓步和恢復的成本,可能比真正在做的事還多,反而更慢。

聰明的做法是「批次處理」,也就是只有在距離上次讓步已經超過一段時間時,才讓一次。常用的門檻就是 50 毫秒——也就是讓工作盡量逼近、但不越過 Long Task 的紅線。實作上,記住上次讓步的時間點,每跑完一小段就比對一下,超過 50 毫秒才讓步並重設計時。這樣既不會切出 Long Task,也不會因為切太碎而拖慢整體。你可以再依需求微調這個門檻,在「回應速度」和「整批跑完的總時間」之間取個平衡。

步驟 6:壓低處理時間與呈現延遲的其他卡點

切 Long Task 主要救的是輸入延遲,但處理時間和呈現延遲也得顧。幾個常見的下手點:

  • 減少事件回呼裡的工作量:回呼裡能少做的就少做,這是最根本的一招。能不能少跑就少跑,永遠勝過事後想辦法切。
  • 避免不必要的重新渲染:像表單輸入這種高頻互動,可以先把狀態存在本地,等到 blur(離開輸入框)這類時機才同步到全域狀態,減少每打一個字就重畫一次的成本。
  • 控制 DOM 規模:DOM 越大,每次更新要算的版面就越多,呈現延遲跟著漲。畫面外的元素可以用 content-visibility 延後渲染。
  • 馴服第三方腳本:廣告、追蹤、客服外掛常常在背景排一堆工作搶主執行緒,能延後載入的就延後、能拿掉的就拿掉。

把這些卡點一個個清掉,三段延遲才會一起降下來。

真的修得動嗎?一個把 INP 砍掉七成的實例

抽象的招式講再多,不如看一個真實數字。一家位於印度的長途巴士訂票網站 redBus,曾經針對 INP 做過一輪認真的優化,結果很有說服力。

他們的搜尋結果頁原本有兩個明顯的卡點。第一個出在延遲載入這件事上——使用者往下捲動時,系統會去 API 抓更多票價,但每次一抓就是一大批,回應又重又慢。他們把每次抓取的筆數從 30 筆降到 10 筆之後,這個頁面的 INP 直接從 870 到 900 毫秒的區間,降到 350 到 370 毫秒——光這一個動作,就把延遲砍掉一半以上。

第二個卡點在輸入框。原本使用者在搜尋頁改個日期、改個條件,每次輸入的 change 事件都會去呼叫一個很重的函式更新整個介面,造成大量不必要的重繪。他們改成把輸入狀態先存在本地,只在離開輸入框時才同步出去,減少了重繪頻率。這一項變更,讓該頁的 INP 又再進步了 72%。

把這些優化加總起來,redBus 的整體銷售額成長了約 7%。這個案例點出兩件事。一是 INP 不是抽象的工程指標,它直接連到使用者願不願意走完流程、最後掏不掏錢;二是真正有效的優化往往不是砍掉某個功能,而是換個方式排程同樣的工作——少抓一點、晚同步一點、讓主執行緒喘口氣,分數就回來了。

INP 優化是一場持續的疊代,不是一次性的衝刺

INP 最容易讓人挫折的地方在於,它不像圖片壓縮那樣改一次就永久有效。它是整頁、整趟使用者旅程累積出來的分數,網站每加一個功能、每塞一個外掛、每接一個第三方腳本,都可能讓某個互動重新變慢。所以與其把它當成一次要清空的待辦,不如把它當成一個要長期盯著的健康指標。

真正的節奏其實很單純:用現場資料找出最慢的那個互動,在開發者工具裡重現它、確認卡在三段延遲的哪一段,再用切工作、讓步、減量這幾招對症下手,改完回頭量一次,然後處理下一個。一輪一輪做下去,分數自然往綠色靠。

回到最前面那個「點下去卻慢半拍」的瞬間,INP 優化真正在練的,其實不是把網站變快,而是學會在對的時刻把主執行緒讓給使用者。當你願意讓那一下,使用者點下去就有回應——而那一下的順暢,往往就是他願意繼續留下來的理由。