window.onload 不觸發的解決辦法
踩坑經歷
昨天我在寫前端代碼時,有個需求是:提交表單后,后台返回一個數據到前端頁面的隱藏域中,在這個頁面加載完成后,判斷這個隱藏域中是否有內容,有則彈出后台返回的信息。我首先想到的就是用 window.onload = function(){...}
的方式在頁面加載完后實現對應的操作。當我測試功能的時候,竟翻車了,window.onload
里面的內容完全不觸發。我也做了其它的測試,包括使用 jQuery 的 ready()
方法和 jQuery 自執行的方法來測試,這些方法能執行,但還是達不到我想要的效果,因為執行這些方法時,我后台的返回的數據還沒有渲染到DOM中。
下面是測試時截圖:
- 使用 alert() 阻塞來判斷
ready()
執行時,頁面情況
- alert() 阻塞時 DOM 元素顯示如下,head 和 body 是空的(可以看到我當時在找着解決方案,捂臉.jpg)
上面的代碼,如果是使用 window.onload,是完全不執行
我也從瀏覽器頁面加載去想這個問題,但仍然想不到哪里出問題了,因為我的 js 代碼都寫在 body 的最下面。
后來找到一篇博客,說頁面元素如果有誤,那么 window.onload 將不會觸發,博客的網址我忘記記錄了,但我確定我的 html 和 css 代碼是沒問題的(因為我是用原本成功的頁面刪減了一些沒用標簽,就這一個頁面用同樣的邏輯寫 window.onload
的方法出問題了)。自己瞎鼓搗了挺久,特別是去檢查了后台數據的傳參(雖然當時知道可能行不大,但萬一呢)。后來我想到了這篇博客說的頁面元素有錯誤,然后我突然有個想法,看看是不是我哪個js 方法寫錯了,然后把除 ready()
和 window.onload
后面的全部方法都注釋掉了,就打算看看這兩個方法會不會觸發。果不其然,它成功運行並達到效果了,困擾我半天的問題終於解決了。順着這個思路下去,尋根溯源,我逐個把每個方法給放出來,最后終於找到了問題所在!我之前寫過了一個 window.onload
的方法!兩個window.onload
方法,默認會執行后面那個方法,所以我之前怎么測試都不觸發的原因就是因為寫了多個 window.onload 方法。(之前 js代碼 是直接復制過來修改的,沒有注意到這個細節,而且這兩個 window.onload
相隔了很多 js 方法)
那為什么 ready()
方法不能將后台的返回到的數據渲染到 DOM 呢?
那就得從 window.onload
和 jQuery 的 ready()
方法的區別來講了。
-
window.onload
所有元素加載完畢后才執行,包括圖片、CSS等所願元素,無許考慮加載的次序問題,且只能執行一次。
-
$(document).ready() 或者 $(function(){...}) 或者 (function(){...})(jQuery );
DOM樹加載完成后執行,不需要等到所有元素加載完畢,且可以執行多次。
如果這兩個的還不是很懂的話,我們這里就講下瀏覽器的加載順序:
瀏覽器的加載和渲染順序是自上而下的,遇到 link,script 等會暫停解析,將控制權交給 JavaScript 解析,執行完畢之后再交給瀏覽器渲染引擎。詳細的渲染步驟如下:
- 加載 html
- 解析器解析html
- 創建 DOM 樹 ,加載CSS(加載完之后才能向下執行)
- 解析 CSS,講 CSS 作用於 DOM 節點上
- 遇到 js,先下載,如果操作了已經渲染完成的元素,則重新渲染
- 遇到圖片資源,向服務器發送請求,無需等待,繼續向下執行
- 返回圖片后,重新渲染這部分代碼
- 顯示所有渲染完成的畫面
從 html 渲染步驟我們可以看出,jQuery 的 ready()
方法是在第三步完成時執行的, window.onload
是在第八步時執行的。也就是說,jQuery 的 ready()
方法主要比 window.onload
先執行的,而 DOM 樹加載完成后,數據並不一定會加載完成。所以我之前的代碼,ready()
方法中不能將后台的返回到的數據渲染到 DOM 就是這個原因。后台返回的數據是在 DOM 樹創建完成后才修改 DOM 元素的。
那么這兩個方法我們要如何選擇使用呢?
我個人觀點是如果是:需要編寫功能性代碼,需要操作后台返回的數據的使用 window.onload
,因為它不需要考慮加載順序的問題,jQuery 的 ready()
方法能做的 window.onload
基本都能做。看起來是不錯,但是比較致命的還是速度問題。很多操作可能並不需要等待全部頁面渲染完成,特別是 CSS、JS、圖片文件比較多或這些文件比較大的頁面,CSS 會阻塞頁面的渲染。所以,大部分場景下,我們使用 jQuery 的 ready()
方法比較多。
講到這里,好像逐漸跑題了,那么我再來總結一下我百度找到的大部分解決方法還有我這個低級錯誤的解決方法吧
解決方案
-
檢查 js 代碼是否有多個
window.onload
,window.onload
只能出現一次! -
使用 jQuery 的
ready()
方法<script type="text/javascript"> // 方式一 $(document).ready(function(){ // 具體操作 }); // 方式二 $(function(){ // 具體操作 }); // 方式三 (function(){ // 具體操作 })(jQuery) </script>
-
從瀏覽器加載順序去思考,找出哪個加載環節出錯,並對應去解決