面試高頻之js的非同步載入 講這個問題之前, 我們從另一個面試高頻問題來切入, 我們的web頁面從開始解析到頁面渲染完成都經歷了什麼 ? 1 , 創建document對象, 開始解析頁面, 此時document.readyState = 'loading' 2 , 遇到link標簽引入的css文件, ...
面試高頻之js的非同步載入
講這個問題之前, 我們從另一個面試高頻問題來切入,
我們的web頁面從開始解析到頁面渲染完成都經歷了什麼 ?
1 , 創建document對象, 開始解析頁面, 此時document.readyState = 'loading'
2 , 遇到link標簽引入的css文件, 創建線程並非同步載入css,繼續解析文檔
3, 遇到script標簽引入的外部腳本 , 如果script標簽的屬性設置了defer或者async 則 創建線程非同步載入js , 否則同步載入js(阻塞了dom的解析) , 繼續解析文檔 (async腳本載入完就執行)
4 , 遇到img等要載入資源的標簽, 正常解析dom 標簽 , 非同步載入src , 繼續解析文檔
5 , 文檔解析完畢 , document.readyState = 'interactive' , 所有defer腳本按順序執行,並且document會觸發 DOMContentLoaded事件 , 標志著程式從同步腳本執行階段轉化成事件驅動階段
6 , 當所有async 腳本 載入並執行 完畢 , img 載入完畢 , document.readyState = 'complete' , window 觸發 load 事件 。
7 從此 以非同步響應的方式處理用戶輸入, 網路事件等 。。。。。。
ok , 光說沒用, 我們來看看真相是否只有一個。。。
document.onreadystatechange = () => { console.log(document.readyState) }; document.addEventListener('DOMContentLoaded', () => { console.log('DOMContentLoaded') }); window.onload = () => { console.log('load') };
註意一點, DOMContentLoaded 事件 只能用 addEventListener 來綁定
結果是這樣:
按順序列印出來了 。。。
上文我們提到只有設置了defer /async 的 script 腳本 才能非同步載入 ,
註意defer 有些低版本瀏覽器不相容,
async是W3C的標準,但只能在引入外部js文件時使用,
當然,我們最常用的是把script標簽放在body 後面 ,這樣就不會阻塞dom解析
還有一種情況, 動態添加的script腳本也是非同步載入的, 基於此 我們來封裝一個 非同步載入script腳本的函數
function loadScript (url, callback) { // 傳入url , 和要執行的回調函數 const script = document.createElement('script'); script.type = 'text/javascript'; // 創建一個script標簽 if (script.readyState) { // 做相容 script.onreadystatechange = () => { // readyState變化觸發 if (script.readyState === 'complete' || script.readyState === 'loaded') { // 相容 callback(); // 載入完執行回調 } } } else { script.onload = () => { callback(); // 載入完執行回調 } } script.src = url; document.head.appendChild(script); // 插入head中 }
以上就是 js 非同步載入 的 全部內容了, 歡迎小伙伴們補充