1、json:?輕量級(jí)的數(shù)據(jù)交換格式;[前后端數(shù)據(jù)傳輸都是json格式的,對(duì)象里面的鍵必須要有雙引號(hào),不可省略;傳輸過(guò)程中json是以字符串進(jìn)行傳輸?shù)?直接對(duì)象形式傳輸不可以,其識(shí)別的是二進(jìn)制,所以傳輸過(guò)程中使用的是二進(jìn)制的文本格式即字符串]
(1).xml:?其是一種語(yǔ)言(xml ->xhtml ->html),最初也作為數(shù)據(jù)交換格式使用,其以標(biāo)簽作為數(shù)據(jù)名,標(biāo)簽內(nèi)容作為數(shù)據(jù)值進(jìn)行傳遞數(shù)據(jù),其可以自定義標(biāo)簽,傳輸效率低下,如今大多使用json;[前后端通信傳遞數(shù)據(jù)是以字符串的形式進(jìn)行,字符串內(nèi)填充數(shù)據(jù),而且數(shù)據(jù)就是對(duì)象的形式,前端給后端傳遞數(shù)據(jù),傳遞的是字符串類型的數(shù)據(jù),后臺(tái)收到進(jìn)行解析成對(duì)象再進(jìn)行一系列的操作(類如:表單數(shù)據(jù)收集),同理后臺(tái)傳遞給前端的數(shù)據(jù)也是字符串格式,需要轉(zhuǎn)化為對(duì)象] [傳遞數(shù)據(jù)需要高效、便捷]
(2).json 是以對(duì)象為樣板,本質(zhì)上就是對(duì)象,在js中“一切都是對(duì)象”,但其和對(duì)象的用途上有區(qū)別,對(duì)象是本地使用(瀏覽器端、服務(wù)器端),json是用來(lái)傳輸?shù)模问缴弦灿袇^(qū)別,json中的屬性必須加雙引號(hào),不可省略;對(duì)象中雙引號(hào)可以省略【區(qū)分json和對(duì)象的要點(diǎn)】
json數(shù)據(jù):var obj = { "name": "abc","age": 18};json字符串:"{ "name": "abc","age": 18}"
(3).以下這兩個(gè)方法很重要:進(jìn)行解析數(shù)據(jù)的第一步【JSON、Math都是靜態(tài)類,使用過(guò)程中不能new +構(gòu)造函數(shù)創(chuàng)建對(duì)象使用;其上有很多屬性和方法,直接使用就OK】
JSON.stringify();? ?json? --->>> string;? ?JSON.parse();? ?string? --->>> json;
[var obj = {name:"nba",age:18} --->> JSON.stringify(obj); -->> "{ "name": "nba","age": 18}", json本質(zhì)也是對(duì)象,目前JSON操作時(shí)也識(shí)別為json對(duì)象]
2、異步加載:前面談到html和css是異步加載,js是同步加載,加載到j(luò)s部分阻塞頁(yè)面的加載直到j(luò)s加載完成,所謂異步加載:工具類/數(shù)據(jù)初始化的js腳本庫(kù)異步加載,操作dom元素的js腳本進(jìn)行同步加載即可;(操作dom元素的js腳本若是異步加載,每次改動(dòng)必然會(huì)影響domTree,進(jìn)而影響randerTree,耗費(fèi)性能); 【js是單線程,若是雙線程,一個(gè)線程增加dom元素,一個(gè)線程刪除dom元素,執(zhí)行哪個(gè)?
瀏覽器內(nèi)核中有渲染引擎和js引擎,渲染頁(yè)面的過(guò)程是怎樣的?html、css、js文件執(zhí)行順序是怎么樣的呢?
頭部引入的css文件和html是異步線程執(zhí)行,引入的js文件和html是同步執(zhí)行:js文件加載完成后,html才能接著進(jìn)行解析,也就是js會(huì)阻塞后面的dom解析(若遇到網(wǎng)速不好等情況,整個(gè)網(wǎng)站將等待js庫(kù)加載而不進(jìn)行后續(xù)渲染);日常開(kāi)發(fā)中,一些工具類的js庫(kù)、引入的第三方庫(kù),我們希望其可以同時(shí)進(jìn)行加載,沒(méi)必要阻塞dom解析,影響頁(yè)面效率,最好采用異步加載的方式;
(1).接下來(lái)先分析一些頁(yè)面渲染過(guò)程:(結(jié)合原生js小結(jié)圖示過(guò)程)
[1].渲染引擎是一行行(按像素點(diǎn))進(jìn)行渲染頁(yè)面的,代碼中就是一行行執(zhí)行代碼(當(dāng)然并非視覺(jué)編程的順序,有預(yù)編譯過(guò)程),首先它會(huì)進(jìn)行domTree的繪制,遵循“深度優(yōu)先原則”,渲染dom的過(guò)程中,若是存在一些Img標(biāo)簽、a標(biāo)簽等含有src、href屬性,和css樣式有所關(guān)聯(lián)的,內(nèi)部依舊會(huì)繼續(xù)解析dom元素到domTree上,但css相關(guān)樣式也開(kāi)始繪制;
[2].domTree樹(shù)繪制完成后,cssTree的繪制是同時(shí)進(jìn)行的,[1]中只是繪制相關(guān)元素的位置,現(xiàn)在開(kāi)始繪制和domTree有關(guān)的所有樣式;
[3].cssTree樹(shù)繪制完成后,其和domTree會(huì)進(jìn)行結(jié)合形成渲染樹(shù),domTree + cssTree = renderTree;?有了renderTree后,渲染引擎才開(kāi)始按著它開(kāi)始渲染頁(yè)面;
[4].期間<head></head>標(biāo)簽部分引入的js文件,其會(huì)阻塞頁(yè)面的渲染過(guò)程,這里還需要介紹兩個(gè)重要概念:reflow 、 repaint;
????????[4.1] js可以操作html,進(jìn)而也可以間接操作css,每一次操作都會(huì)對(duì)domTree產(chǎn)生影響,domTree一變化,就需要重新繪制domTree、cssTree,這種改變稱為reflow重排(重構(gòu)、重做),很影響性能,這也是我們不要隨便修改html結(jié)構(gòu)的原因[常見(jiàn)可引起重構(gòu)的行為:dom節(jié)點(diǎn)的刪除增加、dom元素的寬高變化、位置變化,display:none -->>> display: block;?改變某個(gè)元素會(huì)對(duì)后續(xù)元素產(chǎn)生一系列影響; offsetWidth? offsetHeight 這兩個(gè)雖是查看元素,但依舊會(huì)對(duì)dom元素產(chǎn)生影響]
????????[4.2]repaint?重繪,其區(qū)別于reflow,只需要進(jìn)行部分domTree重繪即可,大多是一些樣式的微弱改變,不影響html結(jié)構(gòu),例如字體顏色、背景圖片、背景顏色等等,對(duì)后續(xù)元素也無(wú)影響,對(duì)性能也有影響,但很小;
(2).JS異步加載的三種方法:操作dom元素的還是采取同步加載,對(duì)于工具庫(kù)/初始化數(shù)據(jù)的庫(kù),采取異步加載或者按需加載來(lái)提高頁(yè)面效率;
[1].defer異步加載,只有IE9以下可用,在script標(biāo)簽加入單屬性即可;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?<script type="text/javascript" scr="tools.js" defer="defer"></script>;?其不僅可以引入外部文件,也可以將代碼寫(xiě)入內(nèi)部,<script type="text/javascript" defer="defer">console.log('a');<script>; [不要既引入外部,又在內(nèi)部寫(xiě)代碼]? 缺點(diǎn):雖然可以同時(shí)進(jìn)行加載,但必須等到dom文檔全部解析完才會(huì)被執(zhí)行;【注意:IE6和IE7的異步加載最多只能有2個(gè),當(dāng)多余兩個(gè)的時(shí)候必須等前兩個(gè)加載完才會(huì)加載第三個(gè)】
[2].async ,w3c標(biāo)準(zhǔn),(IE9以下不兼容);<scrip type="text/javascript" src="tools.js" aysnc="aysnc" ></script>;?其只能加載外部腳本,不能把js代碼寫(xiě)在內(nèi)部,同時(shí)其是加載后就執(zhí)行;
如何處理兼容性:封裝在任何瀏覽器都能異步加載腳本庫(kù);
方法一:<script type="text/javascript" aysnc="aysnc" src="tools.js" defer="defer"><script>? ,這種方法不可以,容易引起系統(tǒng)崩盤(pán);
方法二:<script type="text/javascript" aysnc="aysnc" src="tools.js"><script>
<script type="text/javascript" defer="defer" src="tools.js"></script>?這種方式也不合理;
--->>>?開(kāi)發(fā)中采取的方法:進(jìn)行if判斷,if(IE){使用defer}else{使用async}
[3].按需加載:異步加載并且按需加載,什么時(shí)候用到該腳本,什么時(shí)候進(jìn)行加載,不用就不用管它;應(yīng)用場(chǎng)景也很多,例如:有的按鈕用戶很少會(huì)點(diǎn)擊,但卻有產(chǎn)品價(jià)值,而且點(diǎn)擊有可能會(huì)出現(xiàn)很多信息,可以對(duì)其進(jìn)行“按需加載”,用戶點(diǎn)擊的時(shí)候動(dòng)態(tài)加載完畢即可,不一定執(zhí)行到該腳本庫(kù)就阻塞頁(yè)面或異步加載;
按需加載才是最合適的異步加載方案:創(chuàng)建script,插入到html中,加載完畢后callBack;(內(nèi)容較多,附詳細(xì)過(guò)程)
[3.1].?重點(diǎn):創(chuàng)建script標(biāo)簽后,添加script.src="tools.js"時(shí),只是進(jìn)行異步加載,并沒(méi)有執(zhí)行;
-------->>>>>>>代碼跑起來(lái)的時(shí)候會(huì)報(bào)錯(cuò),下載資源需要過(guò)程:發(fā)出請(qǐng)求,等待響應(yīng),響應(yīng)后開(kāi)始反饋資源,期間過(guò)程是以微秒(us)計(jì)算,由于是異步加載,下面的代碼在加載過(guò)程中便開(kāi)始執(zhí)行,執(zhí)行過(guò)程中若是找不到該方法便會(huì)報(bào)錯(cuò);錯(cuò)誤原因:加載時(shí)間大于代碼執(zhí)行時(shí)間;
[3.2]使用定時(shí)器驗(yàn)證上述說(shuō)法:
-------->>>>>代碼可以正常運(yùn)行,加載的時(shí)間受很多因素影響,例如網(wǎng)速不好等,接下來(lái)進(jìn)行一些操作解決bug,等其加載完成后再執(zhí)行代碼;
[3.3].load事件,很多對(duì)象都有l(wèi)oad事件,并非window獨(dú)有(涉及到下載的就有l(wèi)oad事件);表示:下載完成后觸發(fā)事件,兼容性很好,safari/chrome/firefox/opera都兼容,IE瀏覽器也有l(wèi)oad事件,但I(xiàn)E中的script標(biāo)簽上沒(méi)有l(wèi)oad事件;
[3.4].IE使用:?readystatechange事件,IE在script上設(shè)置了狀態(tài)碼readState,隨著加載過(guò)程其的屬性值會(huì)變化;開(kāi)始:script.readyState = "loading",--->>>加載完成后:script.readyState="complated" /? script.readyState="loaded";[IE和高版本的chrome、firefox的script有此事件,但是其他瀏覽器的dom元素上也有此事件和屬性;document.readyState,表示狀態(tài)]
[3.5]封裝兼容性函數(shù):url:引入的腳步庫(kù),callback();?回調(diào)函數(shù),當(dāng)滿足一定條件才執(zhí)行的函數(shù);將script.src=url;換位置的原因是解決bug,防止IE無(wú)法判斷,解釋:IE判斷的標(biāo)準(zhǔn)就是script的狀態(tài)碼是否發(fā)生變化,若是代碼執(zhí)行到script.src=url;?加載速度特別特別快,在執(zhí)行下面的判斷語(yǔ)句前,已經(jīng)加載完成,這時(shí)候script.readyState="complete";?這時(shí)候就那些if條件判斷時(shí),里面的事件就無(wú)法觸發(fā),這時(shí)里面的函數(shù)也無(wú)法執(zhí)行,所以可以先讓其進(jìn)行if條件判斷,然后再加載;
[3.6]封裝兼容性函數(shù)[最終版]:如果只是異步加載腳本庫(kù),傳入url即可,封裝的是較為靈活的,按需加載腳本庫(kù)、函數(shù),callback如果多個(gè)函數(shù),可以以數(shù)組形式傳入,靈活應(yīng)用;
補(bǔ)充:
(1).實(shí)際操作中又報(bào)錯(cuò);解釋:結(jié)合預(yù)編譯的過(guò)程,函數(shù)執(zhí)行前并不能解析函數(shù)內(nèi)部到底有什么內(nèi)容,當(dāng)函數(shù)執(zhí)行時(shí),執(zhí)行到第二個(gè)參數(shù)的時(shí)候,里面的腳本庫(kù)還未加載成功,會(huì)報(bào)錯(cuò);
解決方案1:使用函數(shù)引用作為參數(shù),當(dāng)傳入時(shí)并不會(huì)解析里面的內(nèi)容,用到的時(shí)候才會(huì)解析;
解決方案2: loadScript("tools.js","test()");?第二個(gè)參數(shù)可以為字符串形式,eval();和setInterval();可以將字符串轉(zhuǎn)化為代碼執(zhí)行;不常用,es3.0也不支持eval();
對(duì)象屬性名的方式也可以;(實(shí)操中也可使用)
總結(jié):
(1).渲染引擎解析html/css,js引擎解析javascript代碼,domTree + cssTree = renderTree;渲染引擎開(kāi)始渲染頁(yè)面;
(2).js會(huì)阻塞dom的解析,解析過(guò)程就是識(shí)別dom元素的過(guò)程(domTree包含元素節(jié)點(diǎn)/文本節(jié)點(diǎn)等系列節(jié)點(diǎn),聚焦點(diǎn)為元素節(jié)點(diǎn)),而dom樹(shù)的加載完成包含里面的圖片、a標(biāo)簽的鏈接等都下載完畢,觸發(fā)window.onload,顯然dom解析必然是在dom加載之前完成;
(3).當(dāng)屬性等于屬性值的時(shí)候,可直接寫(xiě)一個(gè)屬性名即可,也稱為單屬性,系統(tǒng)可以識(shí)別,但是最好寫(xiě)成屬性=“屬性值”的寫(xiě)法;
<script type="text/javascript" src="tools.js" defer="defer"></script>
<script type="text/javascript" src="tools.js" defer></script>
3、js時(shí)間線:
(1).創(chuàng)建document對(duì)象,開(kāi)始解析web頁(yè)面。解析HTML元素和他們的文本內(nèi)容后添加Element對(duì)象和Text節(jié)點(diǎn)到文檔中。這個(gè)階段document.readyState = ‘loading’;
(2).遇到link外部css,創(chuàng)建線程加載,并繼續(xù)解析文檔;
(3).遇到script外部js,并且沒(méi)有設(shè)置async、defer,瀏覽器加載,并阻塞,等待js加載完成并執(zhí)行該腳本,然后繼續(xù)解析文檔;
(4).遇到script外部js,并且設(shè)置有async、defer,瀏覽器創(chuàng)建線程加載,并繼續(xù)解析文檔。 對(duì)于async屬性的腳本,腳本加載完成后立即執(zhí)行;(異步禁止使用document.write())
(5).遇到img等,先正常解析dom結(jié)構(gòu),然后瀏覽器異步加載src,并繼續(xù)解析文檔;
(6).當(dāng)文檔解析完成,document.readyState = ‘interactive’;
(7).文檔解析完成后,所有設(shè)置有defer的腳本會(huì)按照順序執(zhí)行。(注意與async的不同,但同樣禁止使用document.write());【defer腳本監(jiān)視的便是document.readyState的狀態(tài)】;
(8).document對(duì)象觸發(fā)DOMContentLoaded事件,這也標(biāo)志著程序執(zhí)行從同步腳本執(zhí)行階段,轉(zhuǎn)化為事件驅(qū)動(dòng)階段;
(9).當(dāng)所有async的腳本加載完成并執(zhí)行后、img等加載完成后,document.readyState =‘complete’,window對(duì)象觸發(fā)load事件;
(10).從此,以異步響應(yīng)方式處理用戶輸入、網(wǎng)絡(luò)事件等。
補(bǔ)充:
[1].關(guān)于document.write();其會(huì)把括號(hào)里的內(nèi)容當(dāng)作是html文檔輸出到頁(yè)面里去,但有兩種特殊情況,1.當(dāng)頁(yè)面全部加載完成,其會(huì)將頁(yè)面內(nèi)容全部清空;2.異步加載過(guò)程中使用也會(huì)將頁(yè)面內(nèi)容清空;【開(kāi)發(fā)中也沒(méi)太大用處,盡量不要使用】
[2].文檔解析完成:domTree解析完成,不同于頁(yè)面加載完成,頁(yè)面加載完成包括randerTree、js都加載完成;(文檔解析完成發(fā)生在頁(yè)面加載完成之前)
[3].事件驅(qū)動(dòng)階段,頁(yè)面加載完成后基本都是都是這個(gè)階段,沒(méi)有事件的為純靜態(tài)頁(yè)面;
[4].window.onload=function(){};?整個(gè)頁(yè)面加載完成后執(zhí)行;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? $(document).ready(function(){ });? jquery中這種方式表示dom解析完就執(zhí)行;document.addEventListener('DOMContentLoaded',function(){},false);? dom解析完成后就執(zhí)行;[此事件沒(méi)有句柄的方式,只能使用addEventListener();]
? ? ? ?如圖也不會(huì)報(bào)錯(cuò),阻斷dom解析進(jìn)行加載,完成后繼續(xù)進(jìn)行dom解析,此事件會(huì)在dom解析完成后開(kāi)始執(zhí)行,所以這種寫(xiě)法沒(méi)錯(cuò),但是不建議;【dom解析目的是生成dom樹(shù),script是標(biāo)簽當(dāng)然也會(huì)存在于dom樹(shù)上,但里面的js代碼是js引擎進(jìn)行解析的,渲染引擎和js引擎功能不同,最后渲染引擎開(kāi)始渲染頁(yè)面,就是視圖所看到的】