1. 程式人生 > >js筆記(非同步載入)

js筆記(非同步載入)

117.json 1.JSON是一種傳輸資料的格式(以物件為樣板,本質上就是物件,但用途有區別,物件就是本地用的,json是用來傳輸的) (1)XML和HTML:XML和HTML都是指令碼語言,都是由標籤標籤的形式的,XML可以自定義標籤,HTML不行 (2)過去以XML這種語言的格式來傳輸資料,如下,利用標籤名和內容表示資料名和資料值 <student>     <name>liu/name>     <age>20</age> </student> 但是現在的傳的資料格式是json也就是物件格式。裡面有什麼就寫什麼,但是為了和物件區分,特定規定出一種json的格式就是讓屬性名必須加雙引號 但是傳的不可能直接是json,其實傳送給後臺,和後臺傳給咱們的也是字串,字串裡邊是json。 2.JSON.parse();  string — >  JSON是個靜態類像math一樣,裡面有很多函式 3.json JSON.stringify(); json — > string 例1:    var deng = {         name:"deng",         age:20,     }     var deng1 = JSON.stringify(deng); //JSON.stringify     -->     "{"name":"deng","age":20}" //JSON.parse(deng1)    -->    {name: "deng", age: 20}

118.非同步載入js 1.瀏覽器有時間線的問題,首先我們輸入網址的時候,先將這個頁面請求過來,再一行一行載入。 在一行一行解析的過程中,html和css是並行一起解析的,html解析的時候會形成domTree的東西,css會形成cssTree,就像這種 <div>     <span></span>     <strong></strong> </div> 上面的程式碼html部分就會形成下面的樹domTree(二叉樹),深度優先原則,還有一個domTree的解析完畢,並不一定意味著domTree的載入完畢          document          html head             body                                 div                 strong   span 同樣css也會有一個對應的樹(和domTree節點對應的),然後兩顆大樹拼在一起,就會形成渲染樹randerTree,渲染樹大致就是,假如domTree中的div標籤,渲染樹中就有這個div多高多寬什麼樣的等 然後才開始繪製頁面 那麼問:什麼時候算是把一個節點掛到這個樹上面去呢,是把圖片下載完了,再把img掛到樹上去,還是讀到img標籤就掛上去呢? 答:不著急下載,系統讀到img標籤了,就會掛到樹上去,這就叫程式碼的解析。        所以是先解析再下載,先把這個東西解析,再同時開啟一個執行緒,非同步的去下載這個東西 那麼: <div></div> <span></span> <img src="xxx.solarge" alt=""> <script type="text/javascript"> </script> 把javascript放在這些下面好處就是,這些東西剛剛解析完畢之後,javascript就可以操作他們了,沒必要等他們下載完之後,所以更快一點 而window觸發load事件之後,那麼就要等到這個頁面所有的圖片,文字等資訊全部下載完之後,也就是,這個頁面所有自動的過程全部完事,就等著使用者互動體驗了,window.onload才能執行,所以效率是最低的 但是也有好處:就是廣告,等到頁面所有載入完事了,再顯示廣告。但是決對不可以將主程式放在window.onload中 當renderTree真正形成完之後,渲染引擎才會真正的繪製頁面,按照render每條規則繪製頁面

2. reflow(重排/重構):當利用js更改html以致會改變domTree,然後render,這叫做reflow(重排)這種效率是最低的,儘量避免,造成重拍的原因有dom節點的刪除,新增,dom節點的寬高變化,位置變化,display:none -->block,offsetWidth,offsetLeft repaint(重繪):只要是改變了,renderTree都會重新構建,不過是基於什麼重新構建,若是基於CSS背景顏色的,不會全改變,會改變那個對應的一部分,影響比較小,重繪的是一部分,不是所有。也會浪費效率,但是浪費的小,可以接受 3.js載入的缺點:載入工具方法(就像初始化什麼的)沒必要阻塞文件,過得js載入會影響頁面效率,一旦網速不好,那麼整個網站將等待js載入而不進行後續渲染工作 (1)js和html和css不能同時載入是因為js會更改html。js是單執行緒一個原因是因為,它可以修改頁面,要是多執行緒,一個執行緒增加節點,另一個執行緒是刪除節點,到底聽哪個不知道 要是寫多個js包的話,那麼風險會越大,因為要是其中一個出問題了,整個頁面就會廢掉,因為js有阻斷頁面的作用,所喲 4.有些工具需要按需載入,用到再載入,不用不載入。

119.非同步載入js三種方式(接118) 1.defer 非同步載入,但要等到dom文件全部解析完才會被執行。只有IE能用 寫了defer,這個javascript就不會阻塞下面文件的執行了,可以和html,css一起執行 例1:當屬性名等於屬性值的時候,就寫個屬性名就行,系統可以識別,但還是按標準寫,全寫了。 <script type = text/javascript src="tool.js" defer="defer"></script>  <==><script type = text/javascript src="tool.js" defer></script> 例2:不僅是外部檔案可以非同步載入,寫成程式碼塊也是可以非同步載入的,當然不能又src,裡面又寫程式碼的 <head>     <meta charset="UTF-8">     <title>lottery</title> <*往下這三行也可是非同步載入*>     <script type = text/javascript defer="defer">         var a = 123;     </script>     </head> 2.aysnc 非同步載入,載入完就執行,async只能載入外部指令碼,不能把js寫在script標籤裡 asynchronous(非同步)  javascriptt and xml -->ajax 例1:這樣可以但是不能將js寫在裡面,不像上一個, <script type="text/javascript" aysnc="aysnc">              </script> 總結:defer是ie用的 aysnc是非ie瀏覽器用的,當然有些ie的高版瀏覽器也是可以用的,defer全部解析完才會被執行,aysnc是載入完就可以執行,defer裡面除了可以引入外部js檔案,也可以讓內部的js檔案變為非同步的,但是aysnc只能載入外部js檔案 問:我要是想要任何瀏覽器都能實現這種非同步載入,怎麼辦? 要是寫在一起會崩潰、衝突,要是寫兩條語句的話,會產生程式碼覆蓋,程式碼重疊,程式碼衝突等的問題,所以解決方法如下,也是最常用的一種方法 3.建立script標籤,插入到DOM中,載入完畢之後callback 燈塔模式:建立一個img標籤,然後這個img標籤作為一個預載入的東西,不去載入到頁面,把src裡面的值複製過來之後,會將img的東西載入過來,形成一個預載入,以後再用的時候就方便了,再拿快取就可以了。 例1:實現了非同步載入的過程,當然也依賴於另外一個script標籤(外邊那個) <script type="text/javascript">     var script = document.createElement('script');     script.type="text/javascript";     script.src="yinrujs.js"; /*這句執行完系統就會下載這個地址裡的東西了,就會開啟一個執行緒非同步的下載裡面的東西了,而且要是程式碼只寫了這麼多的話,永遠都不會執行,只會下載*/     document.head.appendChild(script);/*當你把這個script標籤插入到頁面裡之後才會執行這個東西,才會解析這個指令碼,否則什麼也不幹,*/ </script> 例2:     var script = document.createElement('script');     script.type="text/javascript";     script.src="yinrujs.js";     document.head.appendChild(script);     test();                     //test函式在yinrujs檔案中 //第一行建立,第二行設定,第三行下載,下載需要傳送請求,然後等請求響應完之後,等待請求迴歸資源的過程, //在發生過程中就已經把下面的那幾行執行完了,因為程式執行是非常快的,並且這個載入還是非同步載入的,不會阻塞程式, //所以可能當下面執行test的時候,那個檔案還沒下載完,所以報錯 4.onload當上面那個例子中檔案下載完了就會觸發onload事件 例1: <script type="text/javascript">     var script = document.createElement('script');     script.type="text/javascript";     script.src="yinrujs.js";     document.head.appendChild(script);     script.onload = function(){         test();     } </script> //並且onload相容性非常好,Safari Chrome firefox,opera,都是相容的,然而ie就script身上沒有onload標籤 4.ie的script身上狀態碼:script.readyState,這個屬性一開始有值 script.readyState="loading",它會根據script標籤載入的進度去動態的改變裡面的值,當script標籤載入完之後,裡面的值會變為"complete"或者"loaded" 當狀態碼改變的時候會觸發onreadystatechange 這個時間就是監聽狀態碼的改變     script.onreadystatechange = function(){         if(script.readyState=="complete"||script.readyState == "loaded"){             test();         }     }

5,回撥函式:當滿足一定條件才執行的函式叫做回撥函式,回撥函式有個名字叫做callback,就像上例中的test。 6.相容性寫法最終版 問題1: 就是當處理的特別快的話,那麼那個readyState瞬間就變為complete了,那麼onreadystatechange就不會觸發了, 因為繫結之前就已經變為最終狀態了,就不會在變化了,所以onreadystatechange就不會再執行了, 所以解決方法就是將src放在後面,這樣狀態一定就會改變,因為在後面才會開始下載檔案。 問題2: 當執行函式的時候,要是直接寫loadscript('yinrujs.js',test);會報錯,因為這個時候還沒有載入檔案還沒有執行函式體,不知道test是什麼,所以會報錯, 解決方法就是,寫匿名函式,函式引用讀的時候不會執行裡面,只有在執行時才會執行裡面的程式碼,然後callback就是函式引用,執行時候執行test loadscript('yinrujs.js',function(){         test();     });

js檔案: function test(){     console.log('a'); } 完整版1: <script type="text/javascript">     function loadscript(url,callback){         var script = document.createElement('script');         script.type="text/javascript";         if(script.ready){             script.onreadystatechange = function(){                 if(script.readyState=="complete"||script.readyState == "loaded"){                     callback();                 }             }         }         else{             script.onload = function(){                 callback();             }         }         script.src=url;         document.head.appendChild(script);     }     loadscript('yinrujs.js',function(){         test();     }); </script> 完整版2:eval將裡面的字串當作程式碼來執行,但是不讓用eval,不建議使用 <script type="text/javascript">     function loadscript(url,callback){         var script = document.createElement('script');         script.type="text/javascript";         if(script.ready){             script.onreadystatechange = function(){                 if(script.readyState=="complete"||script.readyState == "loaded"){                     eval(callback);                 }             }         }         else{             script.onload = function(){                 eval(callback);             }         }         script.src=url;         document.head.appendChild(script);     }     loadscript('yinrujs.js',"test()"); </script> 完整版3: <script type="text/javascript">     function loadscript(url,callback){         var script = document.createElement('script');         script.type="text/javascript";         if(script.ready){             script.onreadystatechange = function(){                 if(script.readyState=="complete"||script.readyState == "loaded"){                     tools[callback]()                 }             }         }         else{             script.onload = function(){                 tools[callback]();             }         }         script.src=url;         document.head.appendChild(script);     }     loadscript('yinrujs.js',"test"); </script> js檔案: var tools = {     test : function(){         console.log('a');     },     demo : function(){

    } }

上面的形式其實很複雜的形式,因為: 正常情況下如果只是想非同步載入一個js,只是想載入一個工具庫的話,也可以用這個方法,只是沒有必要傳回調函式callback 在裡面這麼寫,然後監控它,什麼時候這個函式執行完畢,傳送訊號,當有這個訊號的時候在隨便呼叫函式就可以了,如果針對庫裡的某些方法,去按需載入,按需執行 可以將callback更改,你可能覺得載入完之後要呼叫一系列方法,那可以傳個數組進去,然後在裡面修改程式碼,執行陣列