国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
渲染主循環(huán)(main loop)和requestAnimationFrame

轉(zhuǎn)載請注明出處:http://blog.csdn.net/milado_nju/

# Chromium渲染主循環(huán)(mainloop)和requestAnimationFrame

## 概述

曾經(jīng)寫過一段JavaScript代碼,因為涉及到需要循環(huán)調(diào)用某個函數(shù)來實現(xiàn)動畫的功能,很自然地,我想到了使用setInterval函數(shù)(或者setTimeout,大家是否有類似經(jīng)歷呢?),然后心滿意足地很快的搞定。結(jié)束后,朋友幫忙閱讀了一下代碼,他提醒我是不是可以考慮使用requestAnimationFrame。之前一直知道這個函數(shù),也知道一些它的一些優(yōu)點,問題是為什么呢?本著追究到底的精神,決定還是去閱讀一下WebKit相關(guān)代碼和一些相關(guān)文檔,了解它們背后的故事。好吧,本章我將和大家一起來學(xué)習(xí)和探討這背后的故事…

 

## 背景

接觸過JavaScript的讀者應(yīng)該有過了解或者使用setTimeout或者setInterval的經(jīng)歷,其功能是在每個時間間隔之后一次性或者重復(fù)多次執(zhí)行一段JavaScript代碼(稱為回調(diào)函數(shù)),以完成特定的動畫要求。但是,這里面有還有些疑問:

1.      時間間隔應(yīng)該設(shè)置為多少才合適呢?跟屏幕的分辨率有關(guān)系嗎?

2.      設(shè)置的時間間隔會按照預(yù)想的執(zhí)行嗎?動畫會被平滑地顯示出效果嗎?

3.      回調(diào)函數(shù)是復(fù)雜的好還是簡單的好呢?應(yīng)該如何編寫才能效率高呢?

4.      與平臺和瀏覽器相關(guān)嗎?如何適應(yīng)不同平臺呢?

這對setTimeout和setInterval來說很重要。如果對mainloop機制和渲染機制有一定了解的讀者來說,上面這幾條其實是非常難做到地,哪怕是較為接近理想的結(jié)果。

幸運地是,總是有聰明的人來幫助大家解決難題。對問題提出一個漂亮解決方案的是mozilla的Robert O’Callahan。他的靈感和依據(jù)來源于CSS。CSS是知道動畫什么時候發(fā)生,所以能夠較為準確的知道什么時候刷新UI。對于JavaScript來說,是不是也可以根據(jù)類似的機制呢?答案是肯定地。其做法是增加一個新的方法requestAnimationFrame, 該方法告訴瀏覽器JavaScript想發(fā)起一個動畫幀,然后在動畫幀繪制之前,需要做一些動作,這樣瀏覽器可以根據(jù)需要來優(yōu)化自己的mainloop機制和調(diào)用時間點,以達到較好地平衡效果。

好吧,下面來看看mainloop機制及其工作原理。

 

## 渲染mainloop

因為chromium是多進程的結(jié)構(gòu)(參看Chromium多進程架構(gòu)篇),所以,跟一般瀏覽器不一樣的是,Browser進程UI用戶界面的mainloop和Renderer進程的主線程的mainloop不是同一個,分別位于兩個不同的進程,所以UI和渲染可以互相不影響,聽起來這好像很不錯,是的,但是問題依然存在,那就是Renderer進程的渲染工作和JavaScript的執(zhí)行工作都在其主線程中,由mainloop來負責(zé)調(diào)度完成,所以競爭依然存在。

大致過程是一個大的循環(huán)加上一個事件隊列,具體的過程,如下圖所示。當(dāng)隊列中有事件時,從隊列中取出第一個事件,設(shè)置相應(yīng)的狀態(tài)信息,處理該事件及其對應(yīng)的處理函數(shù),直到該函數(shù)處理完后,才重新檢查隊列中是否有事件。如果有,繼續(xù)處理;如果沒有,則繼續(xù)等待。這其中可以看出,如果隊列中事件多的時候,那么很多事件可能來不及處理,從而造成比較大的延時,因而事件的平均等待時間會比較長。同時,如果事件的處理函數(shù)需要的時間很長,就會造成后面的事件一直在等待,同樣會增加事件的平均等待時間。而當(dāng)隊列比較空閑時或者事件的處理函數(shù)需要的時間比較短,則事件的平均等待時間會相對小很多。


##WebKit和Chromium中的實現(xiàn)

理解了mainloop之后,下面來看一看setTimeout和setInterval的實現(xiàn)。

來看一下它們的實現(xiàn):WebKit中setTimeout和setInterval的實現(xiàn)機制是類似的,區(qū)別在于后者是重復(fù)性的,見下圖所示的類圖關(guān)系。

WebKit會為DOM中的每個setTimeout和setInterval的調(diào)用創(chuàng)建一個DOMTimer,而后該對象會由存儲TLS(thread localstorage)中的ThreadTimers負責(zé)管理,其內(nèi)部其實是一個最小堆,每次取timeout時間最小的,同時,時間相同的Timer可以合并。

當(dāng)Timer超時后,Chromium清除該Timer對象,同時調(diào)用相應(yīng)的回調(diào)函數(shù),回調(diào)函數(shù)通常會更新頁面的樣式和布局,這會觸發(fā)relayout,從而觸發(fā)立即重新繪制一個新幀。


結(jié)合上面的描述,我們大致地總結(jié)setTimeout和setInterval主要不足就是:

1.      setTimeout和setInterval從不考慮瀏覽器內(nèi)部發(fā)生了其他什么事,它只要求瀏覽器在某個時間之后調(diào)用它的回調(diào)函數(shù),無論瀏覽器很繁忙或者頁面被隱藏(雖然某些瀏覽器做了這方面的優(yōu)化,例如chromium);

2.      setTimeout和setInterval只要求瀏覽器做什么,而不管瀏覽器能不能做到(例如mainloop有很多事件需要處理),這有點強人所難,而且會帶來極大的資源浪費。舉個例子,例如屏幕的刷新率是60HZ,但是設(shè)置的時間間隔是5ms,其實對用戶來說根本看不到這些變化,但是額外需要消耗更多的CPU資源,太不環(huán)保了…

3.      setTimeout和setInterval可能是編程風(fēng)格方面的考慮。如果每一幀可能在不同的代碼出需要設(shè)置回調(diào)函數(shù),一個方法是統(tǒng)一到一個地方,但是這有點勉為其難,另一個方法是分別用setInterval設(shè)置它們,這個方法的問題是,瀏覽器可能需要計算更多次,刷新更多次的屏幕,唉。

現(xiàn)在再來看看requestAnimationFrame的實現(xiàn),看看其如何解決這些不足之處的。其原理就是其會申請繪制下一幀,至于什么時候不知道,由瀏覽器決定,只需要瀏覽器在繪制下一幀前執(zhí)行其設(shè)置的回調(diào)函數(shù),完成JavaScript對動畫所做的設(shè)置和邏輯即可。基本過程是這樣的:

1.      JavaScript調(diào)用requestAnimationFrame,因而相應(yīng)的webkit和chromium會調(diào)度一個需要繪制下一幀的事件,該事件會將requestAnimationFrame的調(diào)用上下文和回調(diào)函數(shù)記錄下來;

2.      上面的請求會觸發(fā)Chromium更新頁面內(nèi)容的事件,該事件被mainloop調(diào)度處理后,會檢查是否需要調(diào)用動畫的相關(guān)處理,因為有動畫需要處理,所以會依次調(diào)用那些回調(diào)函數(shù),JavaScript引擎會更新相應(yīng)的CSS屬性或者DOM樹修改;

3.      Chromium觸發(fā)重新計算layout(參看layout章節(jié)),更新自己的Renderer樹(參看webkit渲染基礎(chǔ)章節(jié)),而后繪制,完成一幀的渲染。

下圖是一個上述過程對應(yīng)的狀態(tài)轉(zhuǎn)換圖,來源于chromium的官方網(wǎng)站,看著的確比較饒人,可以先理解一下其中幾個主要的概念:

Floortime:指的是繪制下一幀之前需要等待的事件間隔

Invalidation:觸發(fā)重新繪制請求的操作;

scheduleAnimation:JavaScript調(diào)用requestAnimationFrame所引起的WebKit內(nèi)部請求調(diào)度動畫的操作;

這些狀態(tài)的轉(zhuǎn)換倒是說明了,requestAnimationFrame可以很好地和Chromium內(nèi)部的繪制過程結(jié)合,從而達到比較好的性能。


為了實現(xiàn)更好的性能,chromium中對requestAnimationFrame有三個設(shè)計原則

1.      當(dāng)頁面不可見時,其回調(diào)函數(shù)不會被調(diào)用,這可以減少CPU和GPU的使用率,更環(huán)保嘛;

2.      其最大調(diào)用頻率不會超過60hz,無論屏幕的刷新率是多少,因而回調(diào)函數(shù)也不會每秒調(diào)用超過60次,這是因為60FPS已經(jīng)能夠滿足UI流暢的要求了,更頻繁的刷新效果不明顯;

3.      只有當(dāng)頁面真正開始渲染時,回調(diào)函數(shù)才會被調(diào)用。

為了對比二者的性能上的差異,我測試了GuiMark中HTML5Charting Test benchmark,修改里面一些代碼(其缺省使用的是setInterval,改為requestAnimationFrame作對比),從實際測試的效果上看,在Google Chrome中,兩者相差不是特別大,使用了requestAnimationFrame的benchmark的FPS大概只好了1~2FPS,所以chrome對timer機制的優(yōu)化做地應(yīng)該相當(dāng)不錯。如果你遇到了其他差別比較大的例子,歡迎跟我和大家分享。

Google Chrome對其處理的比較好不代表其他瀏覽器也是,所以各位還是在編程時候多考慮考慮,多思考思考,為了更好的性能,為了環(huán)保…

 

## 設(shè)計機制帶來的編程考慮

最后,結(jié)合mainloop和requestAnimationFrame的設(shè)計原理和機制,看一看它們帶給我們在編寫JavaScript代碼時有哪些方面的思考和便利:

1.      回調(diào)函數(shù)不能太大,不能占用太長時間,否則會影響頁面的響應(yīng)和繪制的頻率;

2.      requestAnimationFrame不需要設(shè)置間隔時間,不同刷新率的間隔時間不一樣,這完全由瀏覽器來控制,而不需要JavaScript程序員操心;

3.      回調(diào)函數(shù)無需合并,程序員可以在任意位置設(shè)置回調(diào)函數(shù),它們可以被瀏覽器集中處理,而無需要一個統(tǒng)一的入口。

 

## 源文件目錄

third_party/WebKit/Source/WebCore/page/

  支持requestAnimationFrame,setTimeout和setInterval的絕大多數(shù)基礎(chǔ)設(shè)施都在這里,建議在該目錄下搜索這些關(guān)鍵字即可

third_party/WebKit/Source/WebCore/platform

  Timer方面的一些支持

 

## 參考文獻

1.      http://dev.chromium.org/developers/design-documents/requestAnimationFrame-implementation

2.      http://www.cnblogs.com/rubylouvre/archive/2011/08/22/2148793.html

3.      http://www.nczonline.net/blog/2011/05/03/better-javascript-animations-with-requestAnimationFrame/

4.      https://developer.mozilla.org/en-US/docs/DOM/window.requestAnimationFrame

5.      http://www.w3.org/TR/animation-timing/#requestAnimationFrame

6.      http://creativejs.com/resources/requestAnimationFrame/

7.      http://www.craftymind.com/factory/guimark2/HTML5ChartingTest.html

 

By yongsheng@chromium.org

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
更好的逐幀動畫函數(shù)
Javascript高性能動畫與頁面渲染
給定時器settimeout、setInterval調(diào)用傳遞參數(shù) (javascript)
JavaScript 定時器,定時調(diào)度任務(wù)實現(xiàn)方式
JavascriptsetTimeout無效解決與setInterval的使用
{JS}JavaScript使用Window對象
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服