Web 動畫幀率(FPS)計算

2021-02-08 前端大全

(點擊上方公眾號,可快速關注)

作者: 伯樂在線/chokcoco 

http://web.jobbole.com/93325/

我們知道,動畫其實是由一幀一幀的圖像構成的。有 Web 動畫那麼就會存在該動畫在播放運行時的幀率。而幀率在不同設備不同情況下又是不一樣的。

有的時候,一些複雜或者重要動畫,我們需要實時監控它們的幀率,或者說是需要知道它們在不同設備的運行狀況,從而更好的優化它們,本文就是介紹 Web 動畫幀率(FPS)計算方法。

流暢動畫的標準

首先,理清一些概念。FPS 表示的是每秒鐘畫面更新次數。我們平時所看到的連續畫面都是由一幅幅靜止畫面組成的,每幅畫面稱為一幀,FPS 是描述「幀」變化速度的物理量。

理論上說,FPS 越高,動畫會越流暢,目前大多數設備的屏幕刷新率為 60 次/秒,所以通常來講 FPS 為 60 frame/s 時動畫效果最好,也就是每幀的消耗時間為 16.67ms。

當然,經常玩 FPS 遊戲的朋友肯定知道,吃雞/CSGO 等 FPS 遊戲推薦使用 144HZ 刷新率的顯示器,144Hz 顯示器特指每秒的刷新率達到 144Hz 的顯示器。相較於普通顯示器每秒60的刷新速度,畫面顯示更加流暢。因此144Hz顯示器比較適用於視角時常保持高速運動的第一人稱射擊遊戲。

不過,這個只是顯示器提供的高刷新率特性,對於我們 Web 動畫而言,是否支持還要看瀏覽器,而大多數瀏覽器刷新率為 60 次/秒。

直觀感受,不同幀率的體驗:

幀率能夠達到 50 ~ 60 FPS 的動畫將會相當流暢,讓人倍感舒適;

幀率在 30 ~ 50 FPS 之間的動畫,因各人敏感程度不同,舒適度因人而異;

幀率在 30 FPS 以下的動畫,讓人感覺到明顯的卡頓和不適感;

幀率波動很大的動畫,亦會使人感覺到卡頓。

OK,那麼我們該如何準確的獲取我們頁面動畫當前的 FPS 值呢?

法一:藉助 Chrome 開發者工具

Chrome 提供給開發者的功能十分強大,在開發者工具中,我們進行如下選擇調出 FPS meter 選項:

通過這個按鈕,可以開啟頁面實時 Frame Rate (幀率) 觀測及頁面 GPU 使用率。

缺點


但是這個方法缺點太多了,

因此,我們需要更加智能的方法。

法二:藉助 Frame Timing API

在介紹下面這種方法前,繼續做一些基礎知識的科普。

Blink 內核早期架構

以 Chrome 瀏覽器內核 Blink 渲染頁面為例。對早期的 Chrome 瀏覽器而言,每個頁面 Tab 對應一個獨立的 renderer 進程,Renderer 進程中包含了主線程和合成線程。早期 Chrome 內核架構:

其中,主線程主要負責:

合成線程則主要負責:

OK,雲裡霧裡的,什麼東西。其實知道了這兩個線程之後,下一個概念是釐清 CSS 動畫與 JS 動畫的細微區別(當然它們都是 Web 動畫)。

JS 動畫與 CSS 動畫的細微區別

上面主要想得出的一個結論是。如果我們能夠知道主線程和合成線程每一幀消耗的時間,那麼我們就能大致得出對應的 Web 動畫的幀率。那麼上面說到的 Frame Timing API 是否可以幫助我們拿到這個時間點呢。

什麼是 Frame Timing API ?

Frame Timing API 是 Web Performance Timing API 標準中的其中一位成員。

Web Performance Timing API 是 W3C 推出的一套性能 API 標準,用於幫助開發者對網站各方面的性能進行精確的分析與控制,提升 Web 網站性能。

它包含許多子類 API,完成不同的功能,大致如下(摘自使用性能API快速分析web前端性能,當然你也可以看英文原版介紹:Web Performance Timing API ):

怎麼使用呢?以 Navigation Timing, Performance Timeline, Resource Timing 為例子,對於兼容它的瀏覽器,它以只讀屬性的形式對外暴露掛載在 window.performance 上。

在調試臺 console 中列印 window.performance ,查看其中的 timing 屬性:

這對象內一連串的變量表示什麼呢,它表示我們頁面整個加載過程中每一個重要的時間點,可以詳細看看這張圖:

通過這張圖以及上面的 window.performance.timing,我們就可以輕鬆的統計出頁面每個重要節點的耗時,這就是 Web Performance Timing API 的強大之處,感興趣的可以詳細去研究研究,使用在頁面統計上。

Frame Timing API 示意

好的,終於可以回歸正題,藉助 Web Performance Timing API 中的 Frame Timing API,可以輕鬆的拿到每一幀中,主線程以及合成線程的時間。或者更加容易,直接拿到每一幀的耗時。

獲取 Render 主線程和合成線程的記錄,每條記錄包含的信息基本如下,代碼示意,(參考至Developer feedback needed: Frame Timing API):

var rendererEvents = window.performance.getEntriesByType("renderer");

var compositeThreadEvents = window.performance.getEntriesByType("composite");

或者是:

var observer = new PerformanceObserver(function(list) {

    var perfEntries = list.getEntries();

    for (var i = 0; i < perfEntries.length; i++) {

        console.log("frame: ", perfEntries[i]);

    }

});

// subscribe to Frame Timing

observer.observe({entryTypes: ['frame']});

每條記錄包含的信息基本如下:

{

  sourceFrameNumber: 120,

  startTime: 1342.549374253

  cpuTime: 6.454313323

}

每個記錄都包括唯一的 Frame Number、Frame 開始時間以及 cpuTime 時間。通過計算每一條記錄的 startTime ,我們就可以算出每兩幀間的間隔,從而得到動畫的幀率是否能夠達到 60 FPS。

不過!看看 Web Performance Timing API 整體的兼容性:

Frame Timing API 雖好,但是,現在 Frame Timing API 的兼容性不算很友好,額,不友好到什麼程度呢。還沒有任何瀏覽器支持,處於實驗性階段,屬於面向未來編程。這你 TM 逗我呢?說了這麼久完全不能用…..

法三:藉助 requestAnimationFrame API

費了這麼多筆墨描述 Frame Timing API 但最後因為兼容性問題完全沒辦法使用。不過不代表這麼長篇幅的描述沒有用,從上面的介紹,我們得知,如果我們可以到得到每一幀中的固定一個時間點,那麼兩者相減,也能夠近似得到一幀所消耗的時間。

那麼,我們再另闢蹊徑。這次,我們藉助兼容性不錯的 requestAnimationFrame API。

window.requestAnimationFrame(callback);

requestAnimationFrame 大家應該都不陌生,方法告訴瀏覽器您希望執行動畫並請求瀏覽器調用指定的函數在下一次重繪之前更新動畫。

當你準備好更新屏幕畫面時你就應用此方法。這會要求你的動畫函數在瀏覽器下次重繪前執行。回調的次數常是每秒 60 次,大多數瀏覽器通常匹配 W3C 所建議的刷新率。

使用 requestAnimationFrame 計算 FPS 原理

原理是,正常而言 requestAnimationFrame 這個方法在一秒內會執行 60 次,也就是不掉幀的情況下。假設動畫在時間 A 開始執行,在時間 B 結束,耗時 x ms。而中間 requestAnimationFrame 一共執行了 n 次,則此段動畫的幀率大致為:n / (B – A)。

核心代碼如下,能近似計算每秒頁面幀率,以及我們額外記錄一個 allFrameCount,用於記錄 rAF 的執行次數,用於計算每次動畫的幀率 :

var rAF = function () {

    return (

        window.requestAnimationFrame ||

        window.webkitRequestAnimationFrame ||

        function (callback) {

            window.setTimeout(callback, 1000 / 60);

        }

    );

}();

var frame = 0;

var allFrameCount = 0;

var lastTime = Date.now();

var lastFameTime = Date.now();

var loop = function () {

    var now = Date.now();

    var fs = (now - lastFameTime);

    var fps = Math.round(1000 / fs);

    lastFameTime = now;

    // 不置 0,在動畫的開頭及結尾記錄此值的差值算出 FPS

    allFrameCount++;

    frame++;

    if (now > 1000 + lastTime) {

        var fps = Math.round((frame * 1000) / (now - lastTime));

        console.log(`${new Date()} 1S內 FPS:`, fps);

        frame = 0;

        lastTime = now;

    };

    rAF(loop);

}

 

loop();

OK,尋找一個有動畫不斷運行的頁面進行測試,可以看到代碼運行如下:

這裡,我使用了我之前製作的一個頁面進行了測試,使用 Chrome 同時調出頁面的 FPS meter,對比兩邊的實時 FPS 值,基本吻合。

測試頁面,Solar System。你可以將上面的代碼貼到這個頁面的 console 中,測試一下數據:

對比右上角的 Frame Rate,幀率基本一致。在大部分情況下,這種方法可以很好的得出 Web 動畫的幀率。

如果我們需要統計某個特定動畫過程的幀率,只需要在動畫開始和結尾兩處分別記錄 allFrameCount 這個數值大小,再除以中間消耗的時間,也可以得出特定動畫過程的 FPS 值。

值得注意的是,這個方法計算的結果和真實的幀率肯定是存在誤差的,因為它是將每兩次主線程執行 javascript 的時間間隔當成一幀,而非上面說的主線程加合成線程所消耗的時間為一幀。但是對於現階段而言,算是一種可取的方法。

參考文章

好了,本文到此結束,希望對你有幫助 :)

如果還有什麼疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

覺得本文對你有幫助?請分享給更多人

關注「前端大全」,提升前端技能

相關焦點

  • 剖析 lottie-web 動畫實現原理
    其中 fr、ip、op 在 Lottie 動畫過程中尤為重要,前面提到我們的動畫 Demo 是 0 - 6s,但是 Lottie 是以幀率計算動畫時間的。Demo 中設置的幀率為 30fps,那麼 0 - 6s 也就等同於 0 - 180 幀。2.2 圖層相關信息理解 JSON 外層信息後,再來展開看下 JSON 中 layers 的具體信息,首先  demo[6]  製作動畫細節如下:
  • lottie-web 動畫實現原理
    ,就是用AE做動畫的時候已經預設好,這是多少幀率(fps)的動畫;ip、op:開始、結束幀。,比如總幀數 totalFrames 、幀率 frameMult 等。_isFrozen) { window.requestAnimationFrame(resume); } else { _stopped = true; }}前面我們提到的動畫參數,開始幀為 0/結束幀為 65/幀率為 25fps。requestAnimationFrame 在正常情況下能達到 60 fps(每隔 16.7ms 左右)。
  • 製作60fps的高性能動畫
    寫在前面說到web的高性能動畫,這部分內容其實已經是老生常談的了,不過其中還是有不少比較新的而且非常實用的內容可以和大家分享一下。
  • K歌禮物視頻動畫 web 端實踐及性能優化回顧
    ‍‍‍‍‍‍在隨後的新 pc 主播端項目中我們對直播工具進行重構 (主界面 UI 基於 web 完成),禮物動畫部分由於當時沒有 web 版本的 sdk,為了復用線上已有的動畫資源以及和移動端保持對齊的效果,web 端通過
  • fps幀率是什麼意思?30幀、60幀對畫面影響有多大?會卡?
    fps幀率又是是什麼意思?在講這個問題之前,先科普一下幀、幀數、幀率分別是什麼,因為我們在日常口語習慣或者說不嚴謹的交流中,通常對於幀數( Frames)與幀率( Frame rate)之間都是混淆的。
  • 【分享】60fps怪物行走動畫解析
    首先先我們來了解下幀率幀率(Frame rate)是用於測量顯示幀數的量度。
  • 【沙發管家】fps幀率是什麼意思?30幀、60幀對畫面影響有多大?會卡?
    fps幀率又是是什麼意思?在講這個問題之前,先科普一下幀、幀數、幀率分別是什麼,因為我們在日常口語習慣或者說不嚴謹的交流中,通常對於幀數( Frames)與幀率( Frame rate)之間都是混淆的。
  • 盲猜手遊幀率,90fps能不能被明顯感知?
    遊戲廠商也讓手遊有了更高的fps以適配硬體的改動 。在PC平臺上,那些反應速度比普通人更快的電競選手在高幀數和高刷新率的加持下,高超的遊戲水平得到了更好的發揮。這讓廣大玩家有了這樣的印象——使用高刷新率設備能有不一樣的體驗,並且提高遊戲成績。那麼事實上,在高刷新率的遊戲手機上玩幀率更高的手遊,會有和PC平臺類似的感受嗎?
  • 《王者榮耀》更新,眾多機型新增60fps高幀率模式
    什麼是高幀率模式呢?開啟了高幀率模式後機型能以最高60fps的幀率進行遊戲,而不開啟的話,最高僅能在30fps模式下遊戲,遊戲體驗區別明顯。開啟高幀率模式後,《王者榮耀》最高能在60fps模式下運行官方公告:為了讓玩家們能享受更平滑、更精美的王者榮耀操作畫面體驗,我們這次在設置界面提供了高幀率模式的開關按鈕。
  • 技術科普丨電影放映大揭秘,論幀率的作用
    前文提到的120幀(fps)指的就是幀率的概念,即每秒播放120張圖片。每一幀圖像處理的時間,不考慮各階段延時及Blanking的過程,幀周期內有兩部分主要操作的時間消耗,包括「曝光時間」和「讀圖時間」。
  • Web Animation 製作指南
    Web動畫實現原理Web動畫的實現原理,是利用了人眼的「視覺暫留」現象,在短時間內連續播放數幅靜止的畫面,使肉眼因視覺殘象產生錯覺,而誤以為畫面在「動」。Web動畫中有幾個主要的概念:幀:在動畫過程中,每一幅靜止畫面即為一「幀」。
  • 基礎丨關於「幀率」,至少需要了解這些
    其中,幀率選項(畫面速率)是視頻中所獨有的概念。所謂幀率,指的是相機在1秒鐘內拍攝下多少幅連續的畫面,它的單位是fps,即 frame per second(每秒傳輸幀數)。起初,無聲電影的底片拍攝幀率介於16fps到24fps之間,當有聲電影在1926年推出時,人耳對音頻的變化更敏感,反而削弱人對電影幀率的關注。由於之前很多無聲電影使用22至26fps的幀率播放,因此選擇中間值24fps作為有聲電影的幀率。
  • 新幀的誕生—— 一個高質量25fps 電影母版的製作實例
    但是最終發行的時候,也會需要製作不同幀率的版本。最近的電影軟體技術革新,已經讓我們可以再以更高的要求,來完成這個母版,得到更好的結果。本文我們來講解一下如何轉換得到相對高質量的 25fps 電影版本。背景知識幀率 我們通常所說的幀率就是在一秒鐘時間裡傳輸圖片的個數,通常用 fps (Frames Per Second) 表示。
  • 遊戲中的FPS是什麼?FPS越高越好還是越低越好?
    FPS指的並不是第一人稱射擊遊戲,FPS 是圖像領域中的定義,是指畫面每秒傳輸幀數,通俗來講就是指動畫或視頻的畫面數。 FPS 是測量用於保存、顯示動態視頻的信息數量。每秒鐘幀數愈多,所顯示的動作就會愈流暢。就像在玩吃雞或其他第一人稱遊戲時,滑鼠轉動時畫面會變化,這些畫面的生成就與FPS有關。
  • 4K@60fps+妥妥無問題,《聖歌》DLSS性能實地測試
    不過這個遺憾在3月底4月初隨著針對《聖歌》推出的一個補丁而得到了完美的解決,隨著這一補丁的更新,DLSS功能正式加入了《聖歌》遊戲,根據官方宣稱,這將極大地提升RTX顯卡的玩家在進行《聖歌》遊戲時的幀率,甚至在4K解析度及最高畫質設置下,也能實現60fps+的絕對流暢遊戲標準。事實,果真如此?
  • 如何讓Win10遊戲欄顯示FPS幀率
    流暢與否有一個衡量值叫做幀率,也就是每秒鐘刷新的畫面幀數,簡稱FPS。值越高越流暢,FPS至少不低於30才算有基本的遊戲流暢度吧。PS: 這麼巧,「幀率」的簡稱與「第一人稱射擊」的簡稱都是FPS。在Windows10以前,我們都需要安裝第三方軟體來顯示幀率,例如Fraps。
  • 英特爾十代酷睿處理器頻率多少 玩遊戲幀率穩定嗎
    正所謂高睿頻高幀率,在遊戲運行當中,流暢的遊戲體驗不僅仰賴於GPU對畫面的實時渲染,在大量物理運算、素材加載、邏輯數據的高速處理當中,擁有強大運算頻率的處理器也是必不可少的——只有當畫面渲染和後臺數據運算都能夠及時完成的情況下、幀率與幀生成都處在理想的狀態下,遊戲的遊玩體驗才是真正流暢的。
  • 前端複雜帶交互動畫的lottie-web方案實現
    隨著動畫效果的日益複雜,一些動畫效果存在兼容問題不說,有些也是複雜到難以實現,前端er要花很長時間在動效的coding上。        lottie-web的出現,解放了前端在動效上的生產力。然而,因為對lottie-web來說,動畫的icon、字體、內容、效果、位置等關鍵信息都是存在於該lottie的json文件之中的。
  • 李安新片《半場無戰事》,從 24fps 到 120fps 到底有多牛逼?
    ——展開的,3D 大家都比較了解,4K 解析度的播放設備也逐漸開始應用,iphone6s 能拍攝 4K 視頻,最後這個 120fps 才是李安這次冒險的重頭戲,他這是把電影拍攝的幀率一下子提高了四倍,如果這部電影最終呈現的效果令人滿意,李安帶來的技術革新意義堪比當年的阿凡達在 3D 電影上的技術革新。
  • 碼流幀率、半全雙工、網口速率概念還不懂的進來看!
    什麼是視頻碼流和幀率?視頻碼流是視頻文件編碼後在單位時間內使用的數據流量。也稱為視頻碼率。是視頻畫面質量的最重要部分(摘自百度百科)。我們監控視頻中碼流的單位時間是1秒。1秒=1000毫秒(這個下面用)。那麼視頻圖像會不會像流水一樣勻速地流過呢?肯定不是的。