我試圖更好地理解在瀏覽器中發生 DOM 操作時會發生什么。我找不到很多資源的事情是瀏覽器何時執行重繪和重排(有很多文獻說明重繪或重排是什么,但幾乎沒有關于何時發生)。
非常具體地說,我想知道這樣的代碼:
function clickHandler() {
domElement1.textContent = 'Hello';
domElement2.textContent = 'World';
}
假設變數domElement1和中存盤了兩個 DOM 元素domElement2。該clickHandler函式附加到一個按鈕,并在單擊時更新兩個 DOM 元素的內容。
現在的問題是:這是否可能導致兩次重繪?即瀏覽器僅更新domElement1,顯示螢屏上的更改導致重繪/重流/等,然后更新domElement2導致另一個重繪/重流/等?或者是否保證按鈕的事件處理程式將在實際 DOM 中發生任何更改之前完全執行?
我的猜測是瀏覽器試圖保持每秒 60 幀,理論上這兩種變化可能發生在兩個不同的幀中。那是對的嗎?
uj5u.com熱心網友回復:
瀏覽器重排和瀏覽器重繪是兩個不同但相關的想法。
回流本質上是計算給定元素的偏移量和尺寸,以了解什么來自哪里以及占用多少空間等等。
重繪是回流后的下一個階段。這是在回流階段進行的計算實際用于在螢屏上繪制像素的時候。這個程序有時也稱為光柵化。
第一件事是:重繪僅在主執行緒空閑時發生,即當沒有事件偵聽器、沒有回呼時,只是當前沒有任何內容等待執行。而且,根據我的直覺,重繪僅在先前觸發重排時才會發生。
與此相反,每個 DOM 突變都可能觸發重排,具體取決于底層代碼。
正如你可以推理的那樣,對于任何瀏覽器來說,最天真的方法是在每個DOM 突變后觸發重排(例如domElement1.textContent = 'Hello';,您在上面共享的陳述句)。但正如您可能同意的那樣,這將是非常低效的。
如果一行中有一大堆這樣的陳述句怎么辦?顯然,在這種情況下,瀏覽器最好在整個陳述句塊的最后只進行一次重排,從而避免浪費計算資源。
現在要記住一件事。您可能知道,瀏覽器引擎,尤其是 JavaScript 引擎,在過去幾年中變得極其復雜、精密和智能。如今,他們可以對代碼的精確要求做出極其智能的猜測,然后最終對其進行多種優化,以便以最快的速度運行它。
這些優化包括在不需要時保持回流演算法的執行。每個瀏覽器究竟是如何做到這一點的,這超出了這個答案的范圍,而且顯然是依賴于實作的。Chrome 可能依賴于一種方法,Firefox 依賴于另一種方法,Safari 依賴于另一種方法,依此類推。
深入挖掘每個人的代碼庫并找到它的確切作業方式并沒有任何意義。
但是,如今所有瀏覽器之間都有一個共同點,那就是它們試圖做最少的不必要的作業。這就是現代 JavaScript 成功的原因之一——強大的引擎就在其背后。
因此,要結束這個答案,我會說不,以下代碼幾乎不可能觸發兩次重排:
function clickHandler() {
domElement1.textContent = 'Hello';
domElement2.textContent = 'World';
// Reflow should happen at the end of this function.
}
然而,下面的陳述句可能會觸發它兩次,因為第二個陳述句想知道一些domElement1只有在瀏覽器運行了回流演算法后才能獲得的東西(即到視口頂部邊緣的距離):
function clickHandler() {
domElement1.textContent = 'Hello';
console.log(dom1Element.getBoundingClientRect().top); // Should trigger reflow.
domElement2.textContent = 'World';
// Reflow should happen at the end of this function.
}
注意上面句子中“幾乎”和“可能”的用法。我用它們來強調我不是 100% 確定的事實。我所說的在每一個瀏覽器上確實發生的概率超過 50%,但概率仍然不是 100%。正如我之前所說,發動機的作業方式不同,我不能盲目地告訴你一些我自己從未檢查過的事情。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/510245.html
