本文首發個人博客 - blog.cdswyda.com,轉載務必保留做者和出處,以便追溯和錯誤修正。php
本文關鍵點: window.onload
和 頁面上 ajax
的成功回調到底哪一個先觸發。html
答案是不肯定。ajax
以前遇到一個現象,在父頁面彈出一個Dialog加載一個子頁面,在onload回調中傳遞一個參數給子頁面,子頁面異步ajax成功回調中要使用這個變量。json
然而出現的狀況是在ajax的成功回調中大多數狀況下是取不到這個在onload傳來的值,可是偶爾又是能夠的。瀏覽器
查閱此Dialog源碼,以上邏輯能夠進行以下簡化。異步
父頁面:post
<iframe id="iframe" src="./iframe.html" onload="onLoad()" frameborder="0"></iframe> <script> function onLoad() { console.log('iframe load'); document.getElementsByTagName('iframe')[0].contentWindow.onLoad('load'); } </script>
子頁面:測試
<script> $.ajax('./test.json').done(function (a) { console.log('ajax結果'); console.log(a); }); function onLoad(e) { console.log('window onload') console.log(e); }; </script>
因爲iframe的 onload
即要加載頁面的 window.onload
,所以狀況能夠進一步簡化爲一個頁面中究竟是 window.onload
先觸發仍是 ajax
的成功回調先觸發。this
測試代碼:url
<script> $.ajax('./test.json').done(function (a) { console.log('ajax結果'); console.log(a); }); function onLoad(e) { console.log('window onload') console.log(e); }; window.onload = onLoad; </script>
這個頁面除了在測試的script以前引入了jQuery沒有其餘代碼,應該毫無疑問,是 window.onload
先觸發,以後纔是 ajax
的成功結果。
結果也證實是 window.onload
先觸發,上面代碼在瀏覽器運行結果爲:
// window onload // Event {} // ajax結果 // {}
MDN上關於 window.onload
有以下解釋:
The load event fires at the end of the document loading process. At this point, all of the objects in the document are in the DOM, and all the images, scripts, links and sub-frames have finished loading.
那麼問題就來了,若是必然是 window.onload 先觸發,那麼是不可能出現最開始的問題的。
繼續修改測試代碼,再加上一些東西:
<script> $.ajax('./test.json').done(function (a) { console.log('ajax結果'); console.log(a); }); function onLoad(e) { console.log('window onload') console.log(e); }; window.onload = onLoad; // 其餘代碼xxx // 模擬一個一分鐘循環 var t1 = new Date().getTime(); while(new Date().getTime() - t1 < 1 * 60 * 1000) { document.querySelectorAll('*'); } </script>
寫入一個一分鐘的循環後,結果發生了改變:
// ajax結果 // {} // window onload // Event {}
這麼來看就奇怪了呀, ajax
的成功比 window.onload
先觸發。
關於這個現象,我也沒找到權威的解釋。
本身給了一個「合理」的解析:
window.onload
會在當前任務隊列的最後一個觸發。如最開始的例子,ajax
異步,還沒有給出結果,頁面須要等待的全部內容已經完成,任務隊列爲空,所以 window.onload
觸發。
然後面這個因爲 ajax
後面還有很長的代碼要執行,這段代碼推遲了 onload
的觸發,同時這段代碼還未執行完成時,以前異步的ajax已經返回告終果,成功回調的代碼已經被加到了任務隊列,所以 ajax
回調執行後才觸發 window.onload
。
爲了進一步驗證我上面的想法,那麼只要保證頁面資源執行完成時,ajax尚未解決便可。
所以仍是上面的代碼,可是將請求的內容換成一個真實接口,這個真實接口返回的數據更晚便可。
使用php暫停120s再返回結果,代碼以下:
<?php sleep(120); echo '{"response":"two minutes later."}' ?>
結果倒是如上面估計的同樣:
// window onload // Event {} // ajax結果 // {"response":"two minutes later."}
能夠說明以前的「合理」解釋確實是合理的。
因此異步的 ajax
和 window.onload
到底哪一個會先觸發是不肯定,和你js代碼(或者其餘onload要等待的資源,如一個圖片加載很慢等)以及這個 ajax
的解決時間有關係。
所以這種狀況下的傳值就不能以這種方式進行,能夠換成更穩妥的方式,如直接跨頁面操做或者放在url進行傳遞。