<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當(dāng)前位置: 首頁(yè) - 科技 - 知識(shí)百科 - 正文

        高性能WEB開發(fā)頁(yè)面呈現(xiàn)、重繪、回流。

        來(lái)源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-27 15:37:08
        文檔

        高性能WEB開發(fā)頁(yè)面呈現(xiàn)、重繪、回流。

        高性能WEB開發(fā)頁(yè)面呈現(xiàn)、重繪、回流。:頁(yè)面呈現(xiàn)流程 在討論頁(yè)面重繪、回流之前。需要對(duì)頁(yè)面的呈現(xiàn)流程有些了解,頁(yè)面是怎么把html結(jié)合css等顯示到瀏覽器上的,下面的流程圖顯示了瀏覽器對(duì)頁(yè)面的呈現(xiàn)的處理流程。可能不同的瀏覽器略微會(huì)有些不同。但基本上都是類似的。 1. 瀏覽器把獲取到的html
        推薦度:
        導(dǎo)讀高性能WEB開發(fā)頁(yè)面呈現(xiàn)、重繪、回流。:頁(yè)面呈現(xiàn)流程 在討論頁(yè)面重繪、回流之前。需要對(duì)頁(yè)面的呈現(xiàn)流程有些了解,頁(yè)面是怎么把html結(jié)合css等顯示到瀏覽器上的,下面的流程圖顯示了瀏覽器對(duì)頁(yè)面的呈現(xiàn)的處理流程??赡懿煌臑g覽器略微會(huì)有些不同。但基本上都是類似的。 1. 瀏覽器把獲取到的html
        頁(yè)面呈現(xiàn)流程

        在討論頁(yè)面重繪、回流之前。需要對(duì)頁(yè)面的呈現(xiàn)流程有些了解,頁(yè)面是怎么把html結(jié)合css等顯示到瀏覽器上的,下面的流程圖顯示了瀏覽器對(duì)頁(yè)面的呈現(xiàn)的處理流程??赡懿煌臑g覽器略微會(huì)有些不同。但基本上都是類似的。


        1. 瀏覽器把獲取到的html代碼解析成1個(gè)Dom樹,html中的每個(gè)tag都是Dom樹中的1個(gè)節(jié)點(diǎn),根節(jié)點(diǎn)就是我們常用的document對(duì)象(<html> tag)。dom樹就是我們用firebug或者IE Developer Toolbar等工具看到的html結(jié)構(gòu),里面包含了所有的html tag,包括display:none隱藏,還有用JS動(dòng)態(tài)添加的元素等。

        2. 瀏覽器把所有樣式(主要包括css和瀏覽器的樣式設(shè)置)解析成樣式結(jié)構(gòu)體,在解析的過(guò)程中會(huì)去掉瀏覽器不能識(shí)別的樣式,比如IE會(huì)去掉-moz開頭的樣式,而firefox會(huì)去掉_開頭的樣式。

        3、dom tree和樣式結(jié)構(gòu)體結(jié)合后構(gòu)建呈現(xiàn)樹(render tree),render tree有點(diǎn)類似于dom tree,但其實(shí)區(qū)別有很大,render tree能識(shí)別樣式,render tree中每個(gè)node都有自己的style,而且render tree不包含隱藏的節(jié)點(diǎn)(比如display:none的節(jié)點(diǎn),還有head節(jié)點(diǎn)),因?yàn)檫@些節(jié)點(diǎn)不會(huì)用于呈現(xiàn),而且不會(huì)影響呈現(xiàn)的,所以就不會(huì)包含到render tree中。注意 visibility:hidden隱藏的元素還是會(huì)包含到render tree中的,因?yàn)関isibility:hidden 會(huì)影響布局(layout),會(huì)占有空間。根據(jù)css2的標(biāo)準(zhǔn),render tree中的每個(gè)節(jié)點(diǎn)都稱為box(Box dimensions),box所有屬性:width,height,margin,padding,left,top,border等。

        4. 一旦render tree構(gòu)建完畢后,瀏覽器就可以根據(jù)render tree來(lái)繪制頁(yè)面了。

        回流與重繪

        1. 當(dāng)render tree中的一部分(或全部)因?yàn)樵氐囊?guī)模尺寸,布局,隱藏等改變而需要重新構(gòu)建。這就稱為回流(其實(shí)我覺得叫重新布局更簡(jiǎn)單明了些)。每個(gè)頁(yè)面至少需要一次回流,就是在頁(yè)面第一次加載的時(shí)候。

        2. 當(dāng)render tree中的一些元素需要更新屬性,而這些屬性只是影響元素的外觀,風(fēng)格,而不會(huì)影響布局的,比如background-color。則就叫稱為重繪。
        注:從上面可以看出,回流必將引起重繪,而重繪不一定會(huì)引起回流。

        什么操作會(huì)引起重繪、回流
        其實(shí)任何對(duì)render tree中元素的操作都會(huì)引起回流或者重繪,比如:

        1. 添加、刪除元素(回流+重繪)

        2. 隱藏元素,display:none(回流+重繪),visibility:hidden(只重繪,不回流)

        3. 移動(dòng)元素,比如改變top,left(jquery的animate方法就是,改變top,left不一定會(huì)影響回流),或者移動(dòng)元素到另外1個(gè)父元素中。(重繪+回流)

        4. 對(duì)style的操作(對(duì)不同的屬性操作,影響不一樣)

        5. 還有一種是用戶的操作,比如改變?yōu)g覽器大小,改變?yōu)g覽器的字體大小等(回流+重繪)

        讓我們看看下面的代碼是如何影響回流和重繪的:

        var s = document.body.style; 
        s.padding = "2px"; // 回流+重繪 
        s.border = "1px solid red"; // 再一次 回流+重繪 
        s.color = "blue"; // 再一次重繪 
        s.backgroundColor = "#ccc"; // 再一次 重繪 
        s.fontSize = "14px"; // 再一次 回流+重繪 
        // 添加node,再一次 回流+重繪 
        document.body.appendChild(document.createTextNode('abc!'));

        請(qǐng)注意我上面用了多少個(gè)再一次。

        說(shuō)到這里大家都知道回流比重繪的代價(jià)要更高,回流的花銷跟render tree有多少節(jié)點(diǎn)需要重新構(gòu)建有關(guān)系,假設(shè)你直接操作body,比如在body最前面插入1個(gè)元素,會(huì)導(dǎo)致整個(gè)render tree回流,這樣代價(jià)當(dāng)然會(huì)比較高,但如果是指body后面插入1個(gè)元素,則不會(huì)影響前面元素的回流。

        聰明的瀏覽器

        從上個(gè)實(shí)例代碼中可以看到幾行簡(jiǎn)單的JS代碼就引起了6次左右的回流、重繪。而且我們也知道回流的花銷也不小,如果每句JS操作都去回流重繪的話,瀏覽器可能就會(huì)受不了。所以很多瀏覽器都會(huì)優(yōu)化這些操作,瀏覽器會(huì)維護(hù)1個(gè)隊(duì)列,把所有會(huì)引起回流、重繪的操作放入這個(gè)隊(duì)列,等隊(duì)列中的操作到了一定的數(shù)量或者到了一定的時(shí)間間隔,瀏覽器就會(huì)把flush隊(duì)列,進(jìn)行一個(gè)批處理。這樣就會(huì)讓多次的回流、重繪變成一次回流重繪。

        雖然有了瀏覽器的優(yōu)化,但有時(shí)候我們寫的一些代碼可能會(huì)強(qiáng)制瀏覽器提前flush隊(duì)列,這樣瀏覽器的優(yōu)化可能就起不到作用了。當(dāng)你請(qǐng)求向?yàn)g覽器請(qǐng)求一些style信息的時(shí)候,就會(huì)讓瀏覽器flush隊(duì)列,比如:
        1. offsetTop, offsetLeft, offsetWidth, offsetHeight
        2. scrollTop/Left/Width/Height
        3. clientTop/Left/Width/Height
        4. width,height
        5. 請(qǐng)求了getComputedStyle(), 或者 ie的 currentStyle

        當(dāng)你請(qǐng)求上面的一些屬性的時(shí)候,瀏覽器為了給你最精確的值,需要flush隊(duì)列,因?yàn)殛?duì)列中可能會(huì)有影響到這些值的操作。

        如何減少回流、重繪

        減少回流、重繪其實(shí)就是需要減少對(duì)render tree的操作,并減少對(duì)一些style信息的請(qǐng)求,盡量利用好瀏覽器的優(yōu)化策略。具體方法有:

        1. 不要1個(gè)1個(gè)改變?cè)氐臉邮綄傩?,最好直接改變className,但className是預(yù)先定義好的樣式,不是動(dòng)態(tài)的,如果你要?jiǎng)討B(tài)改變一些樣式,則使用cssText來(lái)改變,見下面代碼:

        // 不好的寫法
        var left = 1;
        var top = 1;
        el.style.left = left + "px";
        el.style.top = top + "px";
        // 比較好的寫法 
        el.className += " className1";
        // 比較好的寫法 
        el.style.cssText += "; left: " + left + "px; top: " + top + "px;";

        2. 讓要操作的元素進(jìn)行"離線處理",處理完后一起更新,這里所謂的"離線處理"即讓元素不存在于render tree中,比如:
        a) 使用documentFragment或div等元素進(jìn)行緩存操作,這個(gè)主要用于添加元素的時(shí)候,大家應(yīng)該都用過(guò),就是先把所有要添加到元素添加到1個(gè)div(這個(gè)div也是新加的),
        最后才把這個(gè)div append到body中。
        b) 先display:none 隱藏元素,然后對(duì)該元素進(jìn)行所有的操作,最后再顯示該元素。因?qū)isplay:none的元素進(jìn)行操作不會(huì)引起回流、重繪。所以只要操作只會(huì)有2次回流。

        3 不要經(jīng)常訪問會(huì)引起瀏覽器flush隊(duì)列的屬性,如果你確實(shí)要訪問,就先讀取到變量中進(jìn)行緩存,以后用的時(shí)候直接讀取變量就可以了,見下面代碼:

        // 別這樣寫,大哥
        for(循環(huán)) {
         el.style.left = el.offsetLeft + 5 + "px";
         el.style.top = el.offsetTop + 5 + "px";
        }
        // 這樣寫好點(diǎn)
        var left = el.offsetLeft,top = el.offsetTop,s = el.style;
        for(循環(huán)) {
         left += 10;
         top += 10;
         s.left = left + "px";
         s.top = top + "px";
        }

        4. 考慮你的操作會(huì)影響到render tree中的多少節(jié)點(diǎn)以及影響的方式,影響越多,花費(fèi)肯定就越多。比如現(xiàn)在很多人使用jquery的animate方法移動(dòng)元素來(lái)展示一些動(dòng)畫效果,想想下面2種移動(dòng)的方法:

        // block1是position:absolute 定位的元素,它移動(dòng)會(huì)影響到它父元素下的所有子元素。

        // 因?yàn)樵谒苿?dòng)過(guò)程中,所有子元素需要判斷block1的z-index是否在自己的上面,
        // 如果是在自己的上面,則需要重繪,這里不會(huì)引起回流
        $("#block1").animate({left:50});

        // block2是相對(duì)定位的元素,這個(gè)影響的元素與block1一樣,但是因?yàn)閎lock2非絕對(duì)定位
        // 而且改變的是marginLeft屬性,所以這里每次改變不但會(huì)影響重繪,
        // 還會(huì)引起父元素及其下元素的回流

        $("#block2").animate({marginLeft:50});


        實(shí)例測(cè)試

        最后用2個(gè)工具對(duì)上面的理論進(jìn)行一些測(cè)試,這2個(gè)工具是在我 "web 性能測(cè)試工具推薦" 文章中推薦過(guò)的工具,分別是:dynaTrace(測(cè)試ie),Speed Tracer(測(cè)試Chrome)。

        第一個(gè)測(cè)試代碼不改變?cè)氐囊?guī)則,大小,位置。只改變顏色,所以不存在回流,僅測(cè)試重繪,代碼如下:

        <body>
         <script type="text/javascript">
         var s = document.body.style;
         var computed;
         if (document.body.currentStyle) {
         computed = document.body.currentStyle;
         } else {
         computed = document.defaultView.getComputedStyle(document.body, '');
         }
         function testOneByOne(){
         s.color = 'red';;
         tmp = computed.backgroundColor;
         s.color = 'white';
         tmp = computed.backgroundImage;
         s.color = 'green';
         tmp = computed.backgroundAttachment;
         }
         function testAll() {
         s.color = 'yellow';
         s.color = 'pink';
         s.color = 'blue';
         tmp = computed.backgroundColor;
         tmp = computed.backgroundImage;
         tmp = computed.backgroundAttachment;
         }
         </script> 
         color test <br />
         <button onclick="testOneByOne()">Test One by One</button>
         <button onclick="testAll()">Test All</button>
        </body>

        testOneByOne 函數(shù)改變3次color,其中每次改變后調(diào)用getComputedStyle,讀取屬性值(按我們上面的討論,這里會(huì)引起隊(duì)列的flush),testAll 同樣是改變3次color,但是每次改變后并不馬上調(diào)用getComputedStyle。
        我們先點(diǎn)擊Test One by One按鈕,然后點(diǎn)擊 Test All,用dynaTrace監(jiān)控如下:

        20100514005246565.jpg

        上圖可以看到我們執(zhí)行了2次button的click事件,每次click后都跟一次rendering(頁(yè)面重繪),2次click函數(shù)執(zhí)行的時(shí)間都差不多,0.25ms,0.26ms,但其后的rendering時(shí)間就相差一倍多。(這里也可以看出,其實(shí)很多時(shí)候前端的性能瓶頸并不在于JS的執(zhí)行,而是在于頁(yè)面的呈現(xiàn),這種情況在用JS做到富客戶端中更為突出)。我們?cè)倏磮D的下面部分,這是第一次rendering的詳細(xì)信息,可以看到里面有2行是 Scheduleing layout task,這個(gè)就是我們前面討論過(guò)的瀏覽器優(yōu)化過(guò)的隊(duì)列,可以看出我們引發(fā)2次的flush。

        1481872939647491.jpg

        再看第二次rendering的詳細(xì)信息,可以看出并沒有Scheduleing layout task,所以這次rendering的時(shí)間也比較短。


        測(cè)試代碼2:這個(gè)測(cè)試跟第一次測(cè)試的代碼很類似,但加上了對(duì)layout的改變,為的是測(cè)試回流。

        <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
        <html xmlns="http://www.w3.org/1999/xhtml">
        <head>
        </head>
        <body>
         <script type="text/javascript">
         var s = document.body.style;
         var computed;
         if (document.body.currentStyle) {
         computed = document.body.currentStyle;
         } else {
         computed = document.defaultView.getComputedStyle(document.body, '');
         }
         function testOneByOne(){
         s.color = 'red';
         s.padding = '1px';
         tmp = computed.backgroundColor;
         s.color = 'white';
         s.padding = '2px';
         tmp = computed.backgroundImage;
         s.color = 'green';
         s.padding = '3px';
         tmp = computed.backgroundAttachment;
         }
         function testAll() {
         s.color = 'yellow';
         s.padding = '4px';
         s.color = 'pink';
         s.padding = '5px';
         s.color = 'blue';
         s.padding = '6px';
         tmp = computed.backgroundColor;
         tmp = computed.backgroundImage;
         tmp = computed.backgroundAttachment;
         }
         </script> 
         color test <br />
         <button onclick="testOneByOne()">Test One by One</button>
         <button onclick="testAll()">Test All</button>
        </body>

        用dynaTrace監(jiān)控如下:

        20100514005246606.jpg

        相信這圖不用多說(shuō)大家都能看懂了吧,可以看出有了回流后,rendering的時(shí)間相比之前的只重繪,時(shí)間翻了3倍了,可見回流的高成本性啊。
        大家看到時(shí)候注意明細(xì)處相比之前的多了個(gè) Calcalating flow layout。


        最后再使用Speed Tracer測(cè)試一下,其實(shí)結(jié)果是一樣的,只是讓大家了解下2個(gè)測(cè)試工具:

        測(cè)試1:

        20100514005246317.jpg

        圖上第一次點(diǎn)擊執(zhí)行2ms(其中有50% 用于style Recalculation), 第二次1ms,而且第一次click后面也跟了2次style Recalculation,而第二次點(diǎn)擊卻沒有style Recalculation。
        但是這次測(cè)試發(fā)現(xiàn)paint重繪的時(shí)間竟然是一樣的,都是3ms,這可能就是chrome比IE強(qiáng)的地方吧。

        測(cè)試2:

        20100514005246574.jpg

        從圖中竟然發(fā)現(xiàn)第二次的測(cè)試結(jié)果在時(shí)間上跟第一次的完全一樣,這可能是因?yàn)椴僮魈伲鴆hrome又比較強(qiáng)大,所以沒能測(cè)試明顯結(jié)果出來(lái),
        但注意圖中多了1個(gè)紫色部分,就是layout的部分。也就是我們說(shuō)的回流。

        聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        高性能WEB開發(fā)頁(yè)面呈現(xiàn)、重繪、回流。

        高性能WEB開發(fā)頁(yè)面呈現(xiàn)、重繪、回流。:頁(yè)面呈現(xiàn)流程 在討論頁(yè)面重繪、回流之前。需要對(duì)頁(yè)面的呈現(xiàn)流程有些了解,頁(yè)面是怎么把html結(jié)合css等顯示到瀏覽器上的,下面的流程圖顯示了瀏覽器對(duì)頁(yè)面的呈現(xiàn)的處理流程??赡懿煌臑g覽器略微會(huì)有些不同。但基本上都是類似的。 1. 瀏覽器把獲取到的html
        推薦度:
        標(biāo)簽: 顯示 頁(yè)面 性能
        • 熱門焦點(diǎn)

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 亚洲日产无码中文字幕| 色噜噜亚洲精品中文字幕 | 你懂的免费在线观看网站| www亚洲精品少妇裸乳一区二区| 亚洲中文字幕久久精品蜜桃 | 国产午夜鲁丝片AV无码免费 | 中文字幕一精品亚洲无线一区| 美女扒开尿口给男人爽免费视频 | 国产片免费在线观看| 亚洲精品无播放器在线播放| 青春禁区视频在线观看直播免费| 色老板亚洲视频免在线观| 国产卡一卡二卡三免费入口 | 在线观看黄片免费入口不卡| 亚洲欧洲美洲无码精品VA| 亚洲成人免费在线| 天天爽亚洲中文字幕| 美女被免费视频网站a国产| 免费国产va在线观看| 国产V亚洲V天堂A无码| 在线免费观看国产| 亚洲一卡2卡3卡4卡乱码 在线| 日韩精品免费电影| 久久精品无码专区免费| 少妇中文字幕乱码亚洲影视| 黄色永久免费网站| 日日摸日日碰夜夜爽亚洲| 久久夜色精品国产亚洲av| 无码精品国产一区二区三区免费| 亚洲精品中文字幕无乱码| 午夜成人免费视频| A国产一区二区免费入口| 久久亚洲AV成人无码软件| 免费看a级黄色片| 久久久久国色AV免费观看| 91天堂素人精品系列全集亚洲| 国内自产拍自a免费毛片| 中文在线观看国语高清免费| 亚洲成a人片在线观| 亚洲欧洲中文日韩av乱码| 91免费国产自产地址入|