日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 综合教程 >内容正文

综合教程

js脚本加载总结

發(fā)布時(shí)間:2023/12/13 综合教程 23 生活家
生活随笔 收集整理的這篇文章主要介紹了 js脚本加载总结 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

  這段時(shí)間工作工作上不是很緊,零星的在研究瀏覽器的一些東西,剛好這個(gè)月又一次輪到我做沙龍講座了,想好了好久,就來(lái)一次js腳本加載的總結(jié)吧!這一塊應(yīng)該對(duì)于很多做項(xiàng)目的朋友來(lái)會(huì)有所幫助吧!

  1、js起源

  總所周知網(wǎng)頁(yè)最開始的形態(tài)是靜態(tài)的(也就是所謂的靜態(tài)網(wǎng)頁(yè)),那時(shí)候的網(wǎng)頁(yè)主要用于瀏覽資料信息,可是隨著用戶需求的增加,用戶希望在頁(yè)面上做一些交互操作,比如頁(yè)面需要驗(yàn)證才能訪問(wèn)、頁(yè)面輸入的一些數(shù)據(jù)希望下次還可以訪問(wèn)等等,js的出現(xiàn)滿足了人們的需求。也就出現(xiàn)了所謂的動(dòng)態(tài)網(wǎng)頁(yè)。

  雖然js給人們帶來(lái)了很好的交互性,但是起初人們亂用腳本,只是網(wǎng)頁(yè)頁(yè)面代碼混亂不堪,當(dāng)css的出現(xiàn)解決了這一問(wèn)題:

  

  知道如今,我們的網(wǎng)頁(yè)也是分為三部分:HTML(主要放置界面元素)、CSS(主要負(fù)責(zé)界面布局)和JS(主要負(fù)責(zé)界面交互)。

  大家都知道這三部分,但是有很多人不注意一些細(xì)節(jié),導(dǎo)致做出的網(wǎng)頁(yè)訪問(wèn)時(shí)效率低下。在這里我將和大家討論一下關(guān)于js的一些知識(shí),希望給大家?guī)?lái)一定幫助吧!

  2、三種使用腳本方式

  2.1內(nèi)部引用JavaScript

  2.11通過(guò)HTML的script標(biāo)簽加載JavaScript代碼

  如:  

<head>
    <script type="text/javascript">
        document.write("Hello World !");
    </script>
</head>

  2.12通過(guò)注釋隱藏JavaScript代碼

  如:

<head>
    <script type="text/javascript">
        <!--
        document.write("Hello World !");
        //-->
    </script>
</head>

  <!-- ... //-->當(dāng)瀏覽器不支持JavaScript時(shí),屏蔽JavaScript代碼。這個(gè)代碼是駭客技術(shù),<!-- ... -->于HTML注釋,//是JavaScript注釋。當(dāng)瀏覽器支持JavaScript時(shí)//代碼生效,因此HTML的注釋沒有效果;當(dāng)瀏覽器不支JavaScript時(shí),//代碼無(wú)效,因此屏蔽了<!-- ... -->之間的JavaScript代碼。現(xiàn)在這種隱藏JavaScript代碼的方式可以忽略,因?yàn)闆]有瀏覽器不支持JavaScript,除了部分用戶手動(dòng)禁止瀏覽器的JavaScript功能,但是這種情況很少發(fā)生。

  2.1.3使用noscript標(biāo)簽為用戶提供更好的體驗(yàn)

  如:  

<body>
    <script type="text/javascript">
        document.write("Hello World !");
    </script>
    <noscript>
        <p>如果您想查看此網(wǎng)頁(yè),則必須啟用JavaScript。
              然而,JavaScript 似乎被禁用,要么就是您的
              瀏覽器不支持 JavaScript。請(qǐng)更改您的瀏覽器
              選項(xiàng)以啟用 JavaScript,然后刷新。
        </p>
    </noscript>
</body>

  通過(guò)JavaScript注釋的方式可以隱藏JavaScript代碼,通過(guò)noscript標(biāo)簽可以為用戶提供更好的體驗(yàn)(提示用戶你的瀏覽器不支持JavaScript)。

  2.2外部引用JavaScript

  使用<script>標(biāo)簽的src屬性來(lái)加載js腳本。通常JavaScript文件可以使用script標(biāo)簽加載到網(wǎng)頁(yè)的任何一個(gè)地方,但是標(biāo)準(zhǔn)的方式是加載在head標(biāo)簽內(nèi)。為防止網(wǎng)頁(yè)加載緩慢,也可以把非關(guān)鍵的JavaScript放到網(wǎng)頁(yè)底部。 

<script type="text/javascript" src=“SuperMap.js"></script>

  這里有幾點(diǎn)好處:

  1)避免使用<!-- ... //-->,駭客技術(shù)。

  2)統(tǒng)一定義JavaScript代碼,方便查看,方便維護(hù)。

  3)使代碼更安全,可以壓縮,加密單個(gè)JavaScript文件。

  4)瀏覽器可以緩存JavaScript文件,減少寬帶使用。

  2.3內(nèi)聯(lián)引用JavaScript

  內(nèi)聯(lián)引用是通過(guò)HTML標(biāo)簽中的事件屬性實(shí)現(xiàn)的。

<input type="button" value="點(diǎn)我" onclick="alert('你點(diǎn)擊了一個(gè)按鈕');">

  上面示例將調(diào)用input標(biāo)簽的onclick屬性,彈出一個(gè)提示框。

  3內(nèi)外腳本的比較

  內(nèi)聯(lián)腳本方式使用場(chǎng)景很少,幾乎沒什么優(yōu)勢(shì)。

  內(nèi)部腳本示例:http://stevesouders.com/hpws/inlined.php

  外部腳本示例:http://stevesouders.com/hpws/external.php

  內(nèi)部腳本示例只有一個(gè)HTML文檔,其大小為87kb,所有的js和css都包含在HTML文檔自身中。外部腳本示例包含一個(gè)HTML文檔(7kb)、一個(gè)樣式表(59kb)和三個(gè)腳本(1kb、11kb和9kb),總計(jì)87kb。盡管所需下載的總數(shù)據(jù)量是相同的,內(nèi)部腳本示例還是比外部示例快30%到50%。這主要是因?yàn)橥獠渴纠枰袚?dān)多個(gè)HTTP請(qǐng)求帶來(lái)的開銷。盡管外部腳本示例可以從樣式表和腳本的并行下載中獲益,但一個(gè)HTTP請(qǐng)求與五個(gè)HTTP請(qǐng)求之間的差距導(dǎo)致內(nèi)部腳本示例更快一些。

  盡管結(jié)果如此,現(xiàn)實(shí)中還是使用外部文件會(huì)更合理一些,因?yàn)橥獠课募鶐?lái)的收益--------js文件有機(jī)會(huì)被瀏覽器緩存起來(lái)。HTML文檔--------至少是那些包含動(dòng)態(tài)內(nèi)容的HTML文檔--------通常不會(huì)被配置為可以進(jìn)行緩存。當(dāng)遇到這種情況時(shí)(HTML沒有被緩存),每次請(qǐng)求HTML文檔都要下載內(nèi)部的js。另一方面,如果js是外部文件,瀏覽器就能緩存它們,HTML文檔的大小減小,而且不會(huì)增加HTTP請(qǐng)求的數(shù)量。

  關(guān)鍵因素是,與HTML文檔請(qǐng)求數(shù)量相關(guān)的、外部js組件被緩存的頻率。這個(gè)因素盡管難以量化,但可以通過(guò)下面的手段進(jìn)行衡量:

  3.1頁(yè)面查看

  每個(gè)用戶產(chǎn)生的頁(yè)面查看越少,內(nèi)部js的論據(jù)越強(qiáng)勢(shì)。想象一個(gè)普通用戶每個(gè)月只訪問(wèn)你的網(wǎng)站一次。在每次訪問(wèn)之間,外部js文件很可能從瀏覽器的緩存中移除。另一方面,如果普通用戶能夠產(chǎn)生很多的頁(yè)面查看,瀏覽器很可能將外部Js文件放在緩存中。使用外部文件提供js帶來(lái)的收益會(huì)隨著用戶每月的頁(yè)面查看次數(shù)或用戶每會(huì)話產(chǎn)生的頁(yè)面查看次數(shù)的增長(zhǎng)而增加。

  3.2空緩存VS完整緩存

  在比較內(nèi)部和外部文件時(shí),知道用戶緩存外部組件的可能性這一點(diǎn)非常重要。我們?cè)赮ahoo!進(jìn)行了測(cè)量,發(fā)現(xiàn)每天至少攜帶完整緩存訪問(wèn)Yahoo!功能一次的用戶占40%到60%。同樣的研究表明,具有完整緩存額的頁(yè)面查看數(shù)量占75%到85%。注意第一個(gè)統(tǒng)計(jì)測(cè)量的是“唯一用戶”而第二個(gè)是“頁(yè)面查看”。具有完整緩存的頁(yè)面查看所占的百分比比攜帶完整緩存的唯一用戶的百分比高,這是因?yàn)楹芏嘤脩粼谝淮螘?huì)話中進(jìn)行了多次頁(yè)面查看。每天,用戶可能只有開始的一次訪問(wèn)攜帶的是空緩存,之后的多次后續(xù)頁(yè)面查看都具有完整緩存。如果你的網(wǎng)站的本質(zhì)上能夠?yàn)橛脩魩?lái)高完整緩存率,使用外部文件的收益就更大。如果不太可能產(chǎn)生完整緩存,則內(nèi)部腳本是更好的選擇。

  3.3組件重用

  如果你的網(wǎng)站中的每個(gè)頁(yè)面都使用了相同的js,使用外部文件可以提高這些組件的重用率。在這種情況下使用外部文件更加具有優(yōu)勢(shì),因?yàn)楫?dāng)用戶在頁(yè)面間導(dǎo)航時(shí),js組件已經(jīng)位于瀏覽器的緩存中了。相反的情況也很容易理解--------如果沒有任何兩個(gè)頁(yè)面共享相同的js,重用率就會(huì)非常低。難的是絕大多數(shù)網(wǎng)站不是非黑即白的。這就帶來(lái)一個(gè)單獨(dú)相關(guān)的問(wèn)題--------當(dāng)把js打包到外部文件中時(shí),應(yīng)該把邊界劃在哪里?

  

  在典型情況下,頁(yè)面之間的js的重用即不可能100%重疊,也不可能100%無(wú)關(guān)。在這種中間情形中,一個(gè)極端就是為每個(gè)頁(yè)面提供一組分離的外部文件。這種方式的缺點(diǎn)在于,每個(gè)頁(yè)面都強(qiáng)制用戶使用另外一組外部組件并產(chǎn)生令響應(yīng)時(shí)間變慢的HTTP請(qǐng)求。這種方式對(duì)于普通用戶只訪問(wèn)一個(gè)頁(yè)面和很少進(jìn)行跨頁(yè)訪問(wèn)的網(wǎng)站來(lái)說(shuō)是有意義的。

  另一個(gè)極端是創(chuàng)建一個(gè)單獨(dú)的、聯(lián)合了所有js的文件。這只要求用戶生成一個(gè)HTTP請(qǐng)求,但它增加了用戶首次進(jìn)行頁(yè)面查看時(shí)的下載數(shù)據(jù)量。在這種情況下,用戶瀏覽頁(yè)面時(shí)要下載的js多于所需的數(shù)量。而且,在任何一塊獨(dú)立的腳本改變后,都需要更新這個(gè)文件,使所有用戶已經(jīng)緩存了的當(dāng)前版本無(wú)效。這種情況對(duì)于那些每月會(huì)話數(shù)量較高、普通用戶在一個(gè)會(huì)話中訪問(wèn)多個(gè)不同頁(yè)面的網(wǎng)站來(lái)說(shuō)是有意義的。

  如果你的網(wǎng)站不符合這兩種極端情況,最好的答案就是折中。將你的頁(yè)面劃分成幾種頁(yè)面類型,然后為每種類型創(chuàng)建單獨(dú)的腳本,這比維護(hù)一個(gè)單獨(dú)的文件要復(fù)雜,但通常比為每個(gè)頁(yè)面維護(hù)不同的腳本要容易,并且對(duì)于給定的任意頁(yè)面都只需要下載很少的多余的js。

  最后你做出的與js外部文件的邊界相關(guān)的決定影響著組件的重用程度。如果你可以找到一個(gè)平衡點(diǎn),實(shí)現(xiàn)較高的重用性,那么外部文件的論據(jù)更強(qiáng)勢(shì)一些。如果重用度很低,還是內(nèi)部腳本更有意義些。

  在對(duì)于內(nèi)部和外部腳本進(jìn)行比較分析時(shí),關(guān)鍵點(diǎn)在于與HTML文檔請(qǐng)求數(shù)量相關(guān)的外部js組件被緩存的頻率。在此我介紹了三種基準(zhǔn)(頁(yè)面查看、空緩存VS完整緩存和組件重用),這有助于你確定最好的選擇。對(duì)于任何網(wǎng)站來(lái)說(shuō),正確答案都依賴于這些基準(zhǔn)。

  大家如果還想更詳細(xì)的了解瀏覽器腳本、css等的一些效率問(wèn)題,可以看《高性能網(wǎng)站建設(shè)指南》,那里面的14條具體的優(yōu)化原則的確很精辟。

  4 將腳本放在底部

  4.1腳本帶來(lái)的問(wèn)題

  下面是一個(gè)腳本放在中部的示例

  http://stevesouders.com/hpws/js-middle.php

  經(jīng)過(guò)編程的腳本下載需要很長(zhǎng)時(shí)間,因此很容易看到問(wèn)題--------頁(yè)面的下半部分要花很長(zhǎng)時(shí)間才能顯示。出現(xiàn)這一現(xiàn)象是因?yàn)槟_本阻塞了并行下載。在回顧了瀏覽器如何并行下載之后,我們?cè)倩剡^(guò)頭解決這一問(wèn)題。

  4.2并行下載

  對(duì)響應(yīng)時(shí)間影響最大的是頁(yè)面中組件的數(shù)量。當(dāng)緩存為空,每個(gè)組件都會(huì)產(chǎn)生一個(gè)HTTP請(qǐng)求,有時(shí)即便緩存是完整的亦是如此。要知道瀏覽器會(huì)并行地執(zhí)行HTTP請(qǐng)求,你可能會(huì)問(wèn),為什么HTTP請(qǐng)求的數(shù)量會(huì)影響響應(yīng)時(shí)間呢?瀏覽器不能一次將它們都下載下來(lái)嗎?

  對(duì)此的解釋要回到HTTP 1.1規(guī)范,該規(guī)范建議瀏覽器從每個(gè)主機(jī)名并行下載兩個(gè)組件。很多web頁(yè)面需要從一個(gè)主機(jī)名下載所有的組件。查看這些HTTP請(qǐng)求會(huì)發(fā)現(xiàn)它們是呈階梯狀的,如圖所示:

  

                      圖4.1

 如果一個(gè)Web頁(yè)面平均地將其組件分別放在兩個(gè)主機(jī)名下,整體響應(yīng)時(shí)間將可以減少大約一半。HTTP請(qǐng)求的行為看起來(lái)會(huì)是圖4.2所示

  

                        圖4.2

  此處可以并行下載四個(gè)組件(每個(gè)主機(jī)名兩個(gè))。為了對(duì)頁(yè)面加載變快的現(xiàn)象給出可視的效果,其中每個(gè)時(shí)間塊的橫向?qū)挾群蛨D4.1是一樣的。

  每個(gè)主機(jī)名并行下載兩個(gè)組件的限制只是一個(gè)建議。默認(rèn)情況下瀏覽器都遵守這一建議,但用戶也可以重寫該默認(rèn)設(shè)置。但增加并行下載數(shù)量并不是沒有開銷的,其優(yōu)劣取決于你的寬帶和CPU速度。

  4.3腳本阻塞下載

  并行下載組件的優(yōu)點(diǎn)是很明顯的。然而,在一些比較舊的瀏覽器在下載腳本時(shí)并行下載實(shí)際上是被禁用的--------即使使用了不同的主機(jī)名,瀏覽器也不會(huì)啟動(dòng)其他的下載。其中一個(gè)原因是,腳本可能使用document.write來(lái)修飾頁(yè)面內(nèi)容,因此瀏覽器會(huì)等待,以確保頁(yè)面能夠恰當(dāng)?shù)牟季帧#ìF(xiàn)在的瀏覽器雖然可以并行下載,但是同樣阻塞布局)在下載腳本時(shí)瀏覽器阻塞并行下載的另一個(gè)原因是為了保證腳本能夠按照正確的順序執(zhí)行。如果并行下載多個(gè)腳本,就無(wú)法保證響應(yīng)是按照特定順序到達(dá)瀏覽器的。例如:后面的腳本比頁(yè)面中之前出現(xiàn)的腳本更小,它可能首先執(zhí)行。如果它們之間存在著依賴關(guān)系,不按照順序執(zhí)行就會(huì)導(dǎo)致js錯(cuò)誤。

  如下是一個(gè)例子:

  http://stevesouders.com/hpws/js-blocking.php

  該頁(yè)面按照順序包含下列組件

    1、來(lái)至host1的一個(gè)圖片

    2、來(lái)至host2的一個(gè)圖片

    3、來(lái)至host1的一個(gè)加載需要大約10秒的腳本

    4、來(lái)至host1的一個(gè)圖片

    5、來(lái)至host2的一個(gè)圖片

  4.4最差情況:將腳本放在頂部

  至此,腳本對(duì)Web頁(yè)面的影響就清楚了:

    1、腳本會(huì)阻塞對(duì)其后面內(nèi)容的呈現(xiàn)

    2、腳本會(huì)阻塞對(duì)其后面組件的下載

  如果將腳本放在頁(yè)面頂部--------正如通常情況那樣--------頁(yè)面中的所有東西都位于腳本之后,整個(gè)頁(yè)面的呈現(xiàn)和下載都會(huì)被阻塞,直到腳本加載完畢腳本放在頂部的示例:

  http://stevesouders.com/hpws/js-top.php

  由于整個(gè)頁(yè)面的呈現(xiàn)被阻塞,因此導(dǎo)致了白屏現(xiàn)象。逐步呈現(xiàn)對(duì)于良好的用戶體驗(yàn)來(lái)說(shuō)是非常重要的,但緩慢的腳本下載延遲了用戶所期待的反饋。

  4.5最佳情況:將腳本放在底部

  放置腳本的最好地方時(shí)頁(yè)面的底部。這不會(huì)阻止頁(yè)面內(nèi)容的呈現(xiàn),而且頁(yè)面中的可是組件可以盡早下載。腳本放在底部的示例:

  http://stevesouders.com/hpws/js-bottom.php

  把兩個(gè)頁(yè)面--------腳本放在頂部的和腳本放在底部的--------并列放在一起瀏覽,其對(duì)比更為突出。可以在下面這個(gè)示例中看到這一點(diǎn):

  http://stevesouders.com/hpws/move-scripts.php

  4.6正確地放置

  前面那些示例是使用了大概需要10秒才能下載完的腳本。希望你使用的腳本不需要這么長(zhǎng)時(shí)間的延遲,但一個(gè)腳本很可能花費(fèi)比預(yù)期長(zhǎng)的時(shí)間,用戶的寬帶也會(huì)影響腳本的響應(yīng)時(shí)間。你的頁(yè)面中的腳本所產(chǎn)生的影響可能沒有這里展示的那么嚴(yán)重,但仍需要注意。在頁(yè)面中包含多個(gè)腳本也會(huì)帶來(lái)問(wèn)題。

  在很多情況下,很難將腳本移到底部。例如,如果腳本使用document.write向頁(yè)面中插入了內(nèi)容,就不能將其移動(dòng)到頁(yè)面中靠后的位置。

  經(jīng)常出現(xiàn)的另外一種建議是使用延遲腳本。Defer屬性表明腳本不包含document.write,瀏覽器得到這一線索就可繼續(xù)進(jìn)行呈現(xiàn)。從下面的示例可以看到這一點(diǎn):

  http://stevesouders.com/hpws/js-defer.php

  但是不保險(xiǎn),有一些老的瀏覽器不能識(shí)別defer,所以最好還是將腳本放于底部。

 5動(dòng)態(tài)加載腳本

  詳見我之前的博客

js動(dòng)態(tài)加載腳本

  6三種實(shí)用方式

  6.1異步批量添加外部腳本

  很多時(shí)候我們由于產(chǎn)品模塊的劃分,一個(gè)頁(yè)面可能需要加載幾個(gè)腳本,我們需要考慮兩點(diǎn):1、腳本之間是否有依賴關(guān)系,如果存在依賴關(guān)系即使我們使用script標(biāo)簽是按照順序的,但是并行下載是一起下載的,如果出現(xiàn)后面的包先下載完,那么執(zhí)行腳本時(shí)就可能出現(xiàn)錯(cuò)誤;2、考慮到效率,一般情況下異步加載比同步加載會(huì)快一些。為了解決如上問(wèn)題,我們可以利用之前討論的知識(shí)進(jìn)行組合

<html>
<head>
    <title></title>
    <script type="text/javascript">
        function init()
        {
            //這里第一個(gè)參數(shù)是一個(gè)數(shù)組,可以任意多個(gè),加載順序按照數(shù)組的順序進(jìn)行保證
            //第二個(gè)參數(shù)是回調(diào)函數(shù),當(dāng)所有包都確認(rèn)加載完畢后需要執(zhí)行的腳本
            //第三個(gè)參數(shù)是script的標(biāo)簽,這個(gè)參數(shù)可以省略,沒有實(shí)質(zhì)意義
            attachScript(["http://www.cnblogs.com/5/loadJS.js","http://www.cnblogs.com/5/package.js"],operation,"yy")();
        }
        function operation()
        {
            //可以運(yùn)行,顯示“成功加載”
            functionOne();
        }
        //異步批量加載腳本,并且根據(jù)數(shù)組urlArray中的url順序來(lái)加載
        function attachScript(urlArray, callback, id) {
            if(urlArray && ((typeof urlArray) == "object"))
            {
                if(urlArray.constructor == Array)
                {
                    if(urlArray.length>1)
                    {
                        var array = urlArray.splice(0,1);
                        return function(){
                            var dataScript = document.createElement('script');
                            dataScript.type = 'text/javascript';
                            if(dataScript.readyState) { //IE
                                dataScript.onreadystatechange = function() {
                                    if(dataScript.readyState == 'complete'|| dataScript.readyState == 'loaded'){
                                        dataScript.onreadystatechange = null;
                                        attachScript(urlArray,callback,id)();
                                    }
                                }
                            } else { //standers
                                dataScript.onload = function() {
                                    attachScript(urlArray,callback,id)();
                                }
                            }
                            dataScript.src = array[0];
                            dataScript.id = id;
                            document.body.appendChild(dataScript);
                        }
                    }
                    else if(urlArray.length == 1)
                    {
                        return function(){
                            var dataScript = document.createElement('script');
                            dataScript.type = 'text/javascript';
                            if(dataScript.readyState) { //IE
                                dataScript.onreadystatechange = function() {
                                    if(dataScript.readyState == 'complete'|| dataScript.readyState == 'loaded'){
                                        dataScript.onreadystatechange = null;
                                        callback();
                                    }
                                }
                            } else { //standers
                                dataScript.onload = function() {
                                    callback();
                                }
                            }
                            dataScript.src = urlArray[0];
                            dataScript.id = id;
                            document.body.appendChild(dataScript);
                        }
                    }
                }
            }
        }

    </script>
</head>
<body>
<input type="button" value="測(cè)試按鈕" onclick="init()"/>
</body>
</html>

  使用很方便,通過(guò)一個(gè)方法attachScript可以加載你的任意多個(gè)有序的ja包,并且下載的時(shí)候還是并行下載,效率上也還不錯(cuò),你可以把這個(gè)方法單獨(dú)打包,方便以后使用,不過(guò)里面的代碼也許需要稍微修改一下,有些地方不嚴(yán)謹(jǐn)哦!  

  6.2同步分類(或模塊)動(dòng)態(tài)加載

  這里的動(dòng)態(tài)加載是指當(dāng)用戶使用到了某個(gè)類或者模塊才去加載,并且加載不是用戶來(lái)控制,而是自動(dòng)的。

  優(yōu)點(diǎn):

    1、同步加載可以很好的保證腳本的依賴關(guān)系

    2、用時(shí)才加載,可以保證基礎(chǔ)包盡量小,提高用戶體驗(yàn)

  缺點(diǎn):

    1、同步加載相對(duì)異步加載來(lái)說(shuō)一般偏慢

    2、在未發(fā)布的情況下不支持Chrome、Opera

  詳細(xì)的說(shuō)明請(qǐng)看:js動(dòng)態(tài)加載腳本之實(shí)用小技巧

  6.3異步分類(或模塊)動(dòng)態(tài)加載

  這里采用回調(diào)函數(shù)形式的異步加載

  優(yōu)點(diǎn):

    1、異步加載速度快

    2、使用回調(diào)函數(shù)也可以保證腳本的良好依賴關(guān)系

    3、同樣時(shí)基礎(chǔ)包小,提高用戶體驗(yàn)

  缺點(diǎn):

    1、調(diào)試不太方便

    2、類被劃分為兩個(gè)部分,劃分難度大

  說(shuō)明:大家如果了解了6.2的同步分模塊加載后發(fā)現(xiàn)最大的缺點(diǎn)在于未發(fā)布的情況下不支持某些瀏覽器,并且代碼的執(zhí)行中途會(huì)強(qiáng)制被阻止,當(dāng)某些代碼下載下來(lái)后在執(zhí)行,這樣的話所有代碼的下載都是呈線性的下載,沒有并行,效率會(huì)比較低。

  不知道大家有木有注意過(guò)百度地圖的包和google地圖的包是如何實(shí)現(xiàn)的,他們實(shí)現(xiàn)方式一樣:基礎(chǔ)包都是大概70到80kb的樣子,比較小(所有地圖功能包加起來(lái)有200到300左右),第一次訪問(wèn)地圖的時(shí)候就比較小,效率快,用戶體驗(yàn)好,但是用戶在地圖上面觸發(fā)了其他復(fù)雜的功能(比如交通換乘)時(shí),你會(huì)發(fā)現(xiàn)它開始下載一些比較小的包,但這些包是并行下載的。它是如何做到的呢?

  其實(shí)基礎(chǔ)包里面已經(jīng)將所有的API都已經(jīng)定義了,如果沒定義,那運(yùn)行到那一塊的時(shí)候?yàn)g覽器肯定會(huì)報(bào)錯(cuò)誤,但是所有功能都在基礎(chǔ)包里不可能那么小,是因?yàn)榘俣鹊幕A(chǔ)包里面定義的所有的接口(API),但是只有簡(jiǎn)單的屬性是真實(shí)可用的,而那些復(fù)雜的方法都是空的,也就是這些方法里面只是負(fù)責(zé)記錄是否執(zhí)行了此方法,那樣這些方法必定代碼很少,所以基礎(chǔ)包就很小,等程序執(zhí)行一遍后再去下載需要的功能模塊,下完后再按照之前記錄的信息重新執(zhí)行一遍,而這些包里面的方法必將覆蓋以前的假的方法,當(dāng)?shù)诙问褂玫臅r(shí)候就執(zhí)行的真正的方法了。

  下面我們來(lái)寫一個(gè)比較簡(jiǎn)單的例子看一下:

  先看一下測(cè)試的頁(yè)面:  

<html>
<head>
    <title></title>
    <script type="text/javascript" src="Core.js"></script>
    <script type="text/javascript">
        var button;
        function init1()
        {
            button =new SuperMap.Control.Button(20,10);
            var height = button.getHeight();
            button.draw();
        }
        function init2()
        {
            button.draw();
        }
    </script>
</head>
<body>
<input type="button" onclick="init1()" value="按鈕" />
<input type="button" onclick="init2()" value="按鈕2" />
</body>
</html>

  這里點(diǎn)擊“按鈕”,初始化了一個(gè)Button的對(duì)象,然后調(diào)用了方法getHeight(真的簡(jiǎn)單方法)和draw(假的復(fù)雜方法,第一次調(diào)用,只是記錄),再次點(diǎn)擊“按鈕2”,調(diào)用方法draw(真的復(fù)雜方法,第二次調(diào)用,假的已經(jīng)被覆蓋了)。

  這里Core.js是基礎(chǔ)包,代碼如下: 

//一下為框架代碼,大家不需要了解
window.SuperMap = {

    VERSION_NUMBER: "Release 6.1.3",

    _getScriptLocation: (function() {
        //SuperMap-6.1.1-8828
        var r = new RegExp("(^|(.*?\\/))(SuperMap(-(\\d{1}\.)*\\d{1}-\\d{4,})?\.js)(\\?|$)"),
            s = document.getElementsByTagName('script'),
            src, m, l = "";
        for(var i=0, len=s.length; i<len; i++) {
            src = s[i].getAttribute('src');
            if(src) {
                var m = src.match(r);
                if(m) {
                    l = m[1];
                    break;
                }
            }
        }
        return (function() { return l; });
    })()
};

SuperMap.Control = SuperMap.Control || {};

SuperMap.Util = SuperMap.Util || {};

SuperMap.Class = function() {
    var len = arguments.length;
    var P = arguments[0];
    var F = arguments[len-1];

    var C = typeof F.initialize == "function" ?  F.initialize : function(){ P.prototype.initialize.apply(this, arguments); };

    if (len > 1) {
        var newArgs = [C, P].concat( Array.prototype.slice.call(arguments).slice(1, len-1), F);
        SuperMap.inherit.apply(null, newArgs);
    } else {
        C.prototype = F;
    }
    return C;
};
SuperMap.inherit = function(C, P) {
    var F = function() {};
    F.prototype = P.prototype;
    C.prototype = new F;
    var i, l, o;
    for(i=2, l=arguments.length; i<l; i++) {
        o = arguments[i];
        if(typeof o === "function") {
            o = o.prototype;
        }
        SuperMap.Util.extend(C.prototype, o);
    }
};

SuperMap.Util = SuperMap.Util || {};
SuperMap.Util.extend = function(destination, source) {
    destination = destination || {};
    if (source) {
        for (var property in source) {
            var value = source[property];
            if (value !== undefined) {
                destination[property] = value;
            }
        }
        var sourceIsEvt = typeof window.Event == "function"
            && source instanceof window.Event;

        if (!sourceIsEvt
            && source.hasOwnProperty && source.hasOwnProperty("toString")) {
            destination.toString = source.toString;
        }
    }
    return destination;
};
SuperMap.Util.copy = function(des, soc) {
    des = des || {};
    var v;
    if(soc) {
        for(var p in des) {
            v = soc[p];
            if(typeof v !== 'undefined') {
                des[p] = v;
            }
        }
    }
};
SuperMap.Util.reset = function(obj) {
    obj = obj || {};
    for(var p in obj) {
        if(obj.hasOwnProperty(p)) {
            if(typeof obj[p] === "object" && obj[p] instanceof Array) {
                for(var i in obj[p]) {
                    if(obj[p][i].destroy) {
                        obj[p][i].destroy();
                    }
                }
                obj[p].length = 0;
            } else if(typeof obj[p] === "object" && obj[p] instanceof Object) {
                if(obj[p].destroy) {
                    obj[p].destroy();
                }
            }
            obj[p] = null;
        }
    }
};
//以下為核心代碼
//加載腳本的方法
SuperMap.Util.loadJs = function(urlArray, callback, id) {
    if(urlArray && ((typeof urlArray) == "object"))
    {
        if(urlArray.constructor == Array)
        {
            if(urlArray.length>1)
            {
                var array = urlArray.splice(0,1);
                return function(){
                    var dataScript = document.createElement('script');
                    dataScript.type = 'text/javascript';
                    if(dataScript.readyState) { //IE
                        dataScript.onreadystatechange = function() {
                            if(dataScript.readyState == 'complete'|| dataScript.readyState == 'loaded'){
                                dataScript.onreadystatechange = null;
                                SuperMap.Util.loadJs(urlArray,callback,id)();
                            }
                        }
                    } else { //standers
                        dataScript.onload = function() {
                            SuperMap.Util.loadJs(urlArray,callback,id)();
                        }
                    }
                    dataScript.src = array[0];
                    dataScript.id = id;
                    document.body.appendChild(dataScript);
                }
            }
            else if(urlArray.length == 1)
            {
                return function(){
                    var dataScript = document.createElement('script');
                    dataScript.type = 'text/javascript';
                    if(dataScript.readyState) { //IE
                        dataScript.onreadystatechange = function() {
                            if(dataScript.readyState == 'complete'|| dataScript.readyState == 'loaded'){
                                dataScript.onreadystatechange = null;
                                callback();
                            }
                        }
                    } else { //standers
                        dataScript.onload = function() {
                            callback();
                        }
                    }
                    dataScript.src = urlArray[0];
                    dataScript.id = id;
                    document.body.appendChild(dataScript);
                }
            }
        }
    }
}
//用于記錄模塊是否加載
SuperMap.Util.IsControl = false;
//按照模塊名稱來(lái)加載腳本
SuperMap.Util.load = function(backName,callbackFunction){
    if(backName == "Control")
    {
        if(SuperMap.Util.IsControl == false)
        {
            SuperMap.Util.loadJs(["Control.js"],callbackFunction,546756)();
        }
        SuperMap.Util.IsControl == true;
    }
    //其他模塊
    else if(...)
    {
      ...
    }
    //....
}
//用于測(cè)試的類 Control模塊
SuperMap.Control.Button = SuperMap.Class({
    w: 0.0,
    h: 0.0,
    initialize: function(w, h) {
        this.w = parseFloat(w);
        this.h = parseFloat(h);
        this.flow = [];
        //需要注冊(cè)一個(gè)回調(diào)函數(shù)
        var c = this;
        SuperMap.Util.load("Control",function(){
            //等加載完腳本后重新執(zhí)行一遍
            c.init();
        });
    },
    getWidth:function()
    {
        return this.w;
    },
    setWidth:function(value)
    {
        this.w = value;
    },
    getHeight:function()
    {
        return this.h;
    },
    setHeight:function(value)
    {
        this.h = value;
    },
    getArea:function() {

        return this.w * this.h;
    },
    clone:function() {
        return new SuperMap.Control.Button(this.w, this.h);
    },
    //假的方法
    draw:function(){
        this.flow.push({method: "draw", arguments: null});
    },
    CLASS_NAME: "SuperMap.Control.Button"
});

  這里的SuperMap.Control.Button類為不完整的類,注意構(gòu)造函數(shù)里面有一個(gè)回調(diào)函數(shù),當(dāng)整個(gè)類加載完后通過(guò)init入口重新執(zhí)行一遍操作,而里面除了draw是假的以外,其他都是真的。

  再來(lái)看一下Control.js模塊:

var Button = SuperMap.Control.Button;
//必須有的入口方法
Button.prototype.init = function()
{
    for(var i = 0;i<this.flow.length;i++)
    {
        //挨個(gè)執(zhí)行
        this[this.flow[i].method](this.flow[i].arguments);
    }
    delete this.flow;
}
//比較復(fù)雜的方法
Button.prototype.draw = function()
{
    //....
    //alert("繪制完畢");
}

  看完思路大家就會(huì)發(fā)現(xiàn)他有自己的缺點(diǎn):我們調(diào)試怎么辦,調(diào)試的時(shí)候獲取的對(duì)象就不是那么明顯了,很不方便;怎么把一個(gè)類劃分成為兩個(gè)部分,這一點(diǎn)特別的難,我不是百度的員工,也不清楚他們的標(biāo)準(zhǔn)。不過(guò)可以猜想他們這樣的有點(diǎn)很明顯:你管我代碼怎么的,反正用戶用起來(lái)發(fā)現(xiàn)效率很快就行,基礎(chǔ)包很小,用到哪塊再加載哪塊,用戶體驗(yàn)特別的好,并行加載,效率快。

  沒有什么是100%滿意的,只要抓住重點(diǎn)就行,百度和google舍棄了調(diào)試的便利以及開發(fā)的簡(jiǎn)易(使程序員痛苦),但是獲得了廣大用戶的良好評(píng)價(jià),這就是他們的目的。

  這里的三點(diǎn)實(shí)用方式希望能給大家給予一定的幫助吧!

  

總結(jié)

以上是生活随笔為你收集整理的js脚本加载总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。