14 js09 json 異步加載 js時間線

1、json:?輕量級的數據交換格式;[前后端數據傳輸都是json格式的,對象里面的鍵必須要有雙引號,不可省略;傳輸過程中json是以字符串進行傳輸的,直接對象形式傳輸不可以,其識別的是二進制,所以傳輸過程中使用的是二進制的文本格式即字符串]

(1).xml:?其是一種語言(xml ->xhtml ->html),最初也作為數據交換格式使用,其以標簽作為數據名,標簽內容作為數據值進行傳遞數據,其可以自定義標簽,傳輸效率低下,如今大多使用json;[前后端通信傳遞數據是以字符串的形式進行,字符串內填充數據,而且數據就是對象的形式,前端給后端傳遞數據,傳遞的是字符串類型的數據,后臺收到進行解析成對象再進行一系列的操作(類如:表單數據收集),同理后臺傳遞給前端的數據也是字符串格式,需要轉化為對象] [傳遞數據需要高效、便捷]

(2).json 是以對象為樣板,本質上就是對象,在js中“一切都是對象”,但其和對象的用途上有區別,對象是本地使用(瀏覽器端、服務器端),json是用來傳輸的,形式上也有區別,json中的屬性必須加雙引號,不可省略;對象中雙引號可以省略【區分json和對象的要點】

json數據:var obj = { "name": "abc","age": 18};json字符串:"{ "name": "abc","age": 18}"

(3).以下這兩個方法很重要:進行解析數據的第一步【JSON、Math都是靜態類,使用過程中不能new +構造函數創建對象使用;其上有很多屬性和方法,直接使用就OK】

JSON.stringify();? ?json? --->>> string;? ?JSON.parse();? ?string? --->>> json;

[var obj = {name:"nba",age:18} --->> JSON.stringify(obj); -->> "{ "name": "nba","age": 18}", json本質也是對象,目前JSON操作時也識別為json對象]

2、異步加載:前面談到html和css是異步加載,js是同步加載,加載到js部分阻塞頁面的加載直到js加載完成,所謂異步加載:工具類/數據初始化的js腳本庫異步加載,操作dom元素的js腳本進行同步加載即可;(操作dom元素的js腳本若是異步加載,每次改動必然會影響domTree,進而影響randerTree,耗費性能); 【js是單線程,若是雙線程,一個線程增加dom元素,一個線程刪除dom元素,執行哪個?

瀏覽器內核中有渲染引擎和js引擎,渲染頁面的過程是怎樣的?html、css、js文件執行順序是怎么樣的呢?

頭部引入的css文件和html是異步線程執行,引入的js文件和html是同步執行:js文件加載完成后,html才能接著進行解析,也就是js會阻塞后面的dom解析(若遇到網速不好等情況,整個網站將等待js庫加載而不進行后續渲染);日常開發中,一些工具類的js庫、引入的第三方庫,我們希望其可以同時進行加載,沒必要阻塞dom解析,影響頁面效率,最好采用異步加載的方式;

(1).接下來先分析一些頁面渲染過程:(結合原生js小結圖示過程)

[1].渲染引擎是一行行(按像素點)進行渲染頁面的,代碼中就是一行行執行代碼(當然并非視覺編程的順序,有預編譯過程),首先它會進行domTree的繪制,遵循“深度優先原則”,渲染dom的過程中,若是存在一些Img標簽、a標簽等含有src、href屬性,和css樣式有所關聯的,內部依舊會繼續解析dom元素到domTree上,但css相關樣式也開始繪制;

[2].domTree樹繪制完成后,cssTree的繪制是同時進行的,[1]中只是繪制相關元素的位置,現在開始繪制和domTree有關的所有樣式;

[3].cssTree樹繪制完成后,其和domTree會進行結合形成渲染樹,domTree + cssTree = renderTree;?有了renderTree后,渲染引擎才開始按著它開始渲染頁面;

[4].期間<head></head>標簽部分引入的js文件,其會阻塞頁面的渲染過程,這里還需要介紹兩個重要概念:reflow 、 repaint;

????????[4.1] js可以操作html,進而也可以間接操作css,每一次操作都會對domTree產生影響,domTree一變化,就需要重新繪制domTree、cssTree,這種改變稱為reflow重排(重構、重做),很影響性能,這也是我們不要隨便修改html結構的原因[常見可引起重構的行為:dom節點的刪除增加、dom元素的寬高變化、位置變化,display:none -->>> display: block;?改變某個元素會對后續元素產生一系列影響; offsetWidth? offsetHeight 這兩個雖是查看元素,但依舊會對dom元素產生影響]

????????[4.2]repaint?重繪,其區別于reflow,只需要進行部分domTree重繪即可,大多是一些樣式的微弱改變,不影響html結構,例如字體顏色、背景圖片、背景顏色等等,對后續元素也無影響,對性能也有影響,但很小;

(2).JS異步加載的三種方法:操作dom元素的還是采取同步加載,對于工具庫/初始化數據的庫,采取異步加載或者按需加載來提高頁面效率;

[1].defer異步加載,只有IE9以下可用,在script標簽加入單屬性即可;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?<script type="text/javascript" scr="tools.js" defer="defer"></script>;?其不僅可以引入外部文件,也可以將代碼寫入內部,<script type="text/javascript" defer="defer">console.log('a');<script>; [不要既引入外部,又在內部寫代碼]? 缺點:雖然可以同時進行加載,但必須等到dom文檔全部解析完才會被執行;【注意:IE6和IE7的異步加載最多只能有2個,當多余兩個的時候必須等前兩個加載完才會加載第三個】

[2].async ,w3c標準,(IE9以下不兼容);<scrip type="text/javascript" src="tools.js" aysnc="aysnc" ></script>;?其只能加載外部腳本,不能把js代碼寫在內部,同時其是加載后就執行;

如何處理兼容性:封裝在任何瀏覽器都能異步加載腳本庫;

方法一:<script type="text/javascript" aysnc="aysnc" src="tools.js" defer="defer"><script>? ,這種方法不可以,容易引起系統崩盤;

方法二:<script type="text/javascript" aysnc="aysnc" src="tools.js"><script>

<script type="text/javascript" defer="defer" src="tools.js"></script>?這種方式也不合理;

--->>>?開發中采取的方法:進行if判斷,if(IE){使用defer}else{使用async}

[3].按需加載:異步加載并且按需加載,什么時候用到該腳本,什么時候進行加載,不用就不用管它;應用場景也很多,例如:有的按鈕用戶很少會點擊,但卻有產品價值,而且點擊有可能會出現很多信息,可以對其進行“按需加載”,用戶點擊的時候動態加載完畢即可,不一定執行到該腳本庫就阻塞頁面或異步加載;

按需加載才是最合適的異步加載方案:創建script,插入到html中,加載完畢后callBack;(內容較多,附詳細過程)

[3.1].?重點:創建script標簽后,添加script.src="tools.js"時,只是進行異步加載,并沒有執行;

-------->>>>>>>代碼跑起來的時候會報錯,下載資源需要過程:發出請求,等待響應,響應后開始反饋資源,期間過程是以微秒(us)計算,由于是異步加載,下面的代碼在加載過程中便開始執行,執行過程中若是找不到該方法便會報錯;錯誤原因:加載時間大于代碼執行時間;

[3.2]使用定時器驗證上述說法:

-------->>>>>代碼可以正常運行,加載的時間受很多因素影響,例如網速不好等,接下來進行一些操作解決bug,等其加載完成后再執行代碼;

[3.3].load事件,很多對象都有load事件,并非window獨有(涉及到下載的就有load事件);表示:下載完成后觸發事件,兼容性很好,safari/chrome/firefox/opera都兼容,IE瀏覽器也有load事件,但IE中的script標簽上沒有load事件;

[3.4].IE使用:?readystatechange事件,IE在script上設置了狀態碼readState,隨著加載過程其的屬性值會變化;開始:script.readyState = "loading",--->>>加載完成后:script.readyState="complated" /? script.readyState="loaded";[IE和高版本的chrome、firefox的script有此事件,但是其他瀏覽器的dom元素上也有此事件和屬性;document.readyState,表示狀態]

[3.5]封裝兼容性函數:url:引入的腳步庫,callback();?回調函數,當滿足一定條件才執行的函數;將script.src=url;換位置的原因是解決bug,防止IE無法判斷,解釋:IE判斷的標準就是script的狀態碼是否發生變化,若是代碼執行到script.src=url;?加載速度特別特別快,在執行下面的判斷語句前,已經加載完成,這時候script.readyState="complete";?這時候就那些if條件判斷時,里面的事件就無法觸發,這時里面的函數也無法執行,所以可以先讓其進行if條件判斷,然后再加載;

[3.6]封裝兼容性函數[最終版]:如果只是異步加載腳本庫,傳入url即可,封裝的是較為靈活的,按需加載腳本庫、函數,callback如果多個函數,可以以數組形式傳入,靈活應用;

補充:

(1).實際操作中又報錯;解釋:結合預編譯的過程,函數執行前并不能解析函數內部到底有什么內容,當函數執行時,執行到第二個參數的時候,里面的腳本庫還未加載成功,會報錯;

解決方案1:使用函數引用作為參數,當傳入時并不會解析里面的內容,用到的時候才會解析;

解決方案2: loadScript("tools.js","test()");?第二個參數可以為字符串形式,eval();和setInterval();可以將字符串轉化為代碼執行;不常用,es3.0也不支持eval();

對象屬性名的方式也可以;(實操中也可使用)

總結:

(1).渲染引擎解析html/css,js引擎解析javascript代碼,domTree + cssTree = renderTree;渲染引擎開始渲染頁面;

(2).js會阻塞dom的解析,解析過程就是識別dom元素的過程(domTree包含元素節點/文本節點等系列節點,聚焦點為元素節點),而dom樹的加載完成包含里面的圖片、a標簽的鏈接等都下載完畢,觸發window.onload,顯然dom解析必然是在dom加載之前完成;

(3).當屬性等于屬性值的時候,可直接寫一個屬性名即可,也稱為單屬性,系統可以識別,但是最好寫成屬性=“屬性值”的寫法;

<script type="text/javascript" src="tools.js" defer="defer"></script>

<script type="text/javascript" src="tools.js" defer></script>


3、js時間線:

(1).創建document對象,開始解析web頁面。解析HTML元素和他們的文本內容后添加Element對象和Text節點到文檔中。這個階段document.readyState = ‘loading’;

(2).遇到link外部css,創建線程加載,并繼續解析文檔;

(3).遇到script外部js,并且沒有設置async、defer,瀏覽器加載,并阻塞,等待js加載完成并執行該腳本,然后繼續解析文檔;

(4).遇到script外部js,并且設置有async、defer,瀏覽器創建線程加載,并繼續解析文檔。 對于async屬性的腳本,腳本加載完成后立即執行;(異步禁止使用document.write())

(5).遇到img等,先正常解析dom結構,然后瀏覽器異步加載src,并繼續解析文檔;

(6).當文檔解析完成,document.readyState = ‘interactive’;

(7).文檔解析完成后,所有設置有defer的腳本會按照順序執行。(注意與async的不同,但同樣禁止使用document.write());【defer腳本監視的便是document.readyState的狀態】;

(8).document對象觸發DOMContentLoaded事件,這也標志著程序執行從同步腳本執行階段,轉化為事件驅動階段;

(9).當所有async的腳本加載完成并執行后、img等加載完成后,document.readyState =‘complete’,window對象觸發load事件;

(10).從此,以異步響應方式處理用戶輸入、網絡事件等。

補充:

[1].關于document.write();其會把括號里的內容當作是html文檔輸出到頁面里去,但有兩種特殊情況,1.當頁面全部加載完成,其會將頁面內容全部清空;2.異步加載過程中使用也會將頁面內容清空;【開發中也沒太大用處,盡量不要使用】

[2].文檔解析完成:domTree解析完成,不同于頁面加載完成,頁面加載完成包括randerTree、js都加載完成;(文檔解析完成發生在頁面加載完成之前)

[3].事件驅動階段,頁面加載完成后基本都是都是這個階段,沒有事件的為純靜態頁面;

[4].window.onload=function(){};?整個頁面加載完成后執行;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? $(document).ready(function(){ });? jquery中這種方式表示dom解析完就執行;document.addEventListener('DOMContentLoaded',function(){},false);? dom解析完成后就執行;[此事件沒有句柄的方式,只能使用addEventListener();]

? ? ? ?如圖也不會報錯,阻斷dom解析進行加載,完成后繼續進行dom解析,此事件會在dom解析完成后開始執行,所以這種寫法沒錯,但是不建議;【dom解析目的是生成dom樹,script是標簽當然也會存在于dom樹上,但里面的js代碼是js引擎進行解析的,渲染引擎和js引擎功能不同,最后渲染引擎開始渲染頁面,就是視圖所看到的】

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容