目錄
實作js非同步載入
总结
首頁 微信小程式 小程式開發 JavaScript的非同步載入詳解

JavaScript的非同步載入詳解

Mar 17, 2018 pm 03:35 PM
javascript js 詳解

這次帶給大家JavaScript的非同步載入詳解,處理JavaScript非同步載入詳解的注意事項有哪些,以下就是實戰案例,一起來看一下。

同步載入的問題

預設的js是同步載入的,這裡的“載入”可以理解成是解析、執行,而不是“下載”,在最新版本的瀏覽器中,瀏覽器對於程式碼請求的資源都是瀑布式的加載,而不是阻塞式的,但是js的執行總是阻塞的。這會引起什麼問題呢?如果我的index頁面要載入一些js,但是其中的某個請求遲遲得不到回應,於是阻塞了後面的js程式碼的執行(同步載入),同時頁面渲染也不能繼續(如果js引入是在head標籤後)。

<script type="text/javascript" src=&#39;http://china-addthis.googlecode.com/svn/trunk/addthis.js&#39;></script>
<script type="text/javascript" src=&#39;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&#39;></script>
this is a test
登入後複製

例如上面的這段程式碼,儲存為index.html文件,頁面的主體是一個簡單的字串,但是程式碼執行後頁面遲遲都是空白,為何?因為請求的js遲遲無法載入(可能由於Google被牆等原因),於是阻塞了後面的程式碼的執行,頁面得不到渲染。可能你會提議,把js程式碼放到前不就能先渲染頁面了!好方法,我們嘗試將js放後面:

this is a test
<script type="text/javascript" src=&#39;http://china-addthis.googlecode.com/svn/trunk/addthis.js&#39;></script>
<script type="text/javascript" src=&#39;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&#39;></script>
登入後複製

頁面瞬間被渲染,「this is a test」也很快出現在前台,世界似乎平靜了,可是:

this is a test
<script type="text/javascript" src=&#39;http://china-addthis.googlecode.com/svn/trunk/addthis.js&#39;></script>
<script type="text/javascript" src=&#39;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&#39;></script>
登入後複製

在前面程式碼的基礎上簡單加了一段程式碼,但是"hello world"遲遲無法在控制台輸出,顯然前面的js請求阻塞了後面程式碼的加載,我們恍然大悟,改變js的載入位置只能改變頁面的渲染,然而對於js的載入並沒有什麼卵用,js還是會阻塞。

實作js非同步載入

我們的要求似乎很簡單,能在頁面載入的同時,在控制台輸出字串即可,再講的通俗一點,就是在請求第一段谷歌提供的js的同時,繼續執行下面的js,也就是實作js的非同步載入。

最常見的做法是動態產生script標籤:

<body>
 this is a test
 <script type="text/javascript">
  ~function() {
   var s = document.createElement('script');
   s.src = 'http://china-addthis.googlecode.com/svn/trunk/addthis.js';
   document.body.appendChild(s);
  }();
 </script>
 <script type="text/javascript" src=&#39;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&#39;></script>
 <script type="text/javascript">
  console.log('hello world');
 </script>
</body>
登入後複製

但是還是有點問題,這種載入方式在載入執行完之前會阻止onload 事件的觸發,而現在很多頁面的程式碼都在onload 時還要執行額外的渲染工作等,所以還是會阻塞部分頁面的初始化處理:

<body>
 this is a test
 <script type="text/javascript">
  ~function() {
   // function async_load() {
    var s = document.createElement('script');
    s.src = 'http://china-addthis.googlecode.com/svn/trunk/addthis.js';
    document.body.appendChild(s);
   // }
   // window.addEventListener('load', async_load, false);
  }();
  window.onload = function() {
   var txt = document.createTextNode(' hello world');
   document.body.appendChild(txt);
  };
 </script>
 <script type="text/javascript" src=&#39;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&#39;></script>
</body>
登入後複製

比如上面的程式碼不能很好地渲染”hello world”,我們只需將註解去掉就可以了,讓Google提供的js在onload 時才開始非同步載入。這樣就解決了阻塞 onload 事件觸發的問題。

補充DOMContentLoaded 與 OnLoad 事件 DOMContentLoaded : 頁面(document)已經解析完成,頁面中的dom元素已經可用。但是頁面中引用的圖片、subframe可能還沒載入完。 OnLoad:頁面的所有資源都加載完畢(包括圖片)。瀏覽器的載入進度在這時才停止。這兩個時間點將頁面載入的timeline分成了三個階段。

以上似乎能較好解決這個問題,但html5提供了更簡單的方法,async屬性!

this is a test
<script type="text/javascript" src=&#39;http://china-addthis.googlecode.com/svn/trunk/addthis.js&#39; async=&#39;async&#39;></script>
<script type="text/javascript" src=&#39;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&#39;></script>
<script type="text/javascript">
 console.log('hello world');
</script>
登入後複製

async是html5的新屬性,async 屬性規定一旦腳本可用,則會非同步執行(一旦下載完畢就會立刻執行)。

要注意的是async 屬性只適用於外部腳本(只有在使用src 屬性時)

defer屬性常常和async一起提起:

this is a test
<script type="text/javascript" src=&#39;http://china-addthis.googlecode.com/svn/trunk/addthis.js&#39; defer=&#39;defer&#39;></script>
<script type="text/javascript" src=&#39;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&#39;></script>
<script type="text/javascript">
 console.log('hello world');
</script>
登入後複製

似乎實現效果差不多,但是真的一樣嗎?我們來看看defer屬性的定義。

以前的defer只支援ie的hack,現在html5的出現開始全面支援defer。 defer 屬性規定當頁面已完成載入後,才會執行腳本。 defer 屬性僅適用於外部腳本(只有在使用 src 屬性時)。 ps:ie支持的defer似乎並非如此,因為對ie無感,不深究,有興趣的可以去查閱相關資料。

既然async和defer常常一起出現,那麼辨識一下吧!

如果沒有async和defer屬性(賦值為true,下同),那麼瀏覽器會立即執行目前的js腳本,阻塞後面的腳本;如果有async屬性,載入和渲染後續文件元素的過程將會和目前js的載入與執行並行進行(非同步);如果有defer屬性,那麼載入後續文件元素的過程將會和script.js 的載入並行進行(非同步),但是script.js 的執行要在所有元素( DOM)解析完成之後,DOMContentLoaded 事件觸發前完成。

来看一张网上盗的图:

蓝色线代表网络读取,红色线代表执行时间,这俩都是针对脚本的;绿色线代表 HTML 解析。

此图告诉我们以下几个要点(摘自defer和async的区别):

  1. defer 和 async 在网络读取(下载)这块儿是一样的,都是异步的(相较于 HTML 解析)

  2. 它俩的差别在于脚本下载完之后何时执行,显然 defer 是最接近我们对于应用脚本加载和执行的要求的

  3. 关于 defer,此图未尽之处在于它是按照加载顺序执行脚本的,这一点要善加利用

  4. async 则是一个乱序执行的主,反正对它来说脚本的加载和执行是紧紧挨着的,所以不管你声明的顺序如何,只要它加载完了就会立刻执行

  5. 仔细想想,async 对于应用脚本的用处不大,因为它完全不考虑依赖(哪怕是最低级的顺序执行),不过它对于那些可以不依赖任何脚本或不被任何脚本依赖的脚本来说却是非常合适的,最典型的例子:Google Analytics

但是在我看来(以下个人理解,如有出入还望指出),defer在异步加载上的应用并不会比async广。async的英文解释是异步,该属性作用在脚本上,使得脚本加载(下载)完后随即开始执行,和动态插入script标签作用类似(async只支持h5,后者能兼容浏览器);而defer的英文解释是延迟,作用也和字面解释类似,延迟脚本的执行,使得dom元素加载完后才开始有序执行脚本,因为有序,所以会带来另一个问题:

this is a test
<script type="text/javascript" src=&#39;http://china-addthis.googlecode.com/svn/trunk/addthis.js&#39; defer=&#39;defer&#39;></script>
<script type="text/javascript" src=&#39;http://libs.baidu.com/jquery/2.0.0/jquery.min.js&#39; defer=&#39;defer&#39;></script>
<script type="text/javascript" src=&#39;index.js&#39; defer=&#39;defer&#39;></script>
console.log('hello world');
登入後複製

如果执行这段代码,控制台的“hello world”也会迟迟得不到结果。所以我觉得还是async好用,如果要考虑依赖的话,可以选择requirejs、seajs等模块加载器。

总结

JavaScript的异步加载还有一些方式,比如:AJAX eval(使用AJAX得到脚本内容,然后通过eval(xmlhttp.responseText)来运行脚本)、iframe方式等。

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

webpack如何动态引入文件

微信小程序的圆形进度条怎么做

以上是JavaScript的非同步載入詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

建議:優秀JS開源人臉偵測辨識項目 建議:優秀JS開源人臉偵測辨識項目 Apr 03, 2024 am 11:55 AM

人臉偵測辨識技術已經是一個比較成熟且應用廣泛的技術。而目前最廣泛的網路應用語言非JS莫屬,在Web前端實現人臉偵測辨識相比後端的人臉辨識有優勢也有弱勢。優點包括減少網路互動、即時識別,大大縮短了使用者等待時間,提高了使用者體驗;弱勢是:受到模型大小限制,其中準確率也有限。如何在web端使用js實現人臉偵測呢?為了實現Web端人臉識別,需要熟悉相關的程式語言和技術,如JavaScript、HTML、CSS、WebRTC等。同時也需要掌握相關的電腦視覺和人工智慧技術。值得注意的是,由於Web端的計

Win11管理員權限取得詳解 Win11管理員權限取得詳解 Mar 08, 2024 pm 03:06 PM

Windows作業系統是全球最受歡迎的作業系統之一,其新版本Win11備受矚目。在Win11系統中,管理員權限的取得是一個重要的操作,管理員權限可以讓使用者對系統進行更多的操作和設定。本文將詳細介紹在Win11系統中如何取得管理員權限,以及如何有效地管理權限。在Win11系統中,管理員權限分為本機管理員和網域管理員兩種。本機管理員是指具有對本機電腦的完全管理權限

Oracle SQL中的除法運算詳解 Oracle SQL中的除法運算詳解 Mar 10, 2024 am 09:51 AM

OracleSQL中的除法運算詳解在OracleSQL中,除法運算是一種常見且重要的數學運算運算,用來計算兩個數相除的結果。除法在資料庫查詢中經常用到,因此了解OracleSQL中的除法運算及其用法是資料庫開發人員必備的技能之一。本文將詳細討論OracleSQL中除法運算的相關知識,並提供具體的程式碼範例供讀者參考。一、OracleSQL中的除法運算

linux系統呼叫system()函數詳解 linux系統呼叫system()函數詳解 Feb 22, 2024 pm 08:21 PM

Linux系統呼叫system()函數詳解系統呼叫是Linux作業系統中非常重要的一部分,它提供了一種與系統核心互動的方式。其中,system()函數是常用的系統呼叫函數之一。本文將詳細介紹system()函數的使用方法,並提供對應的程式碼範例。系統呼叫的基本概念系統呼叫是使用者程式與作業系統核心互動的一種方式。使用者程式透過呼叫系統呼叫函數來請求作業系統

PHP模運算子的作用及用法詳解 PHP模運算子的作用及用法詳解 Mar 19, 2024 pm 04:33 PM

PHP中的模運算子(%)是用來取得兩個數值相除的餘數的。在本文中,我們將詳細討論模運算子的作用及用法,並提供具體的程式碼範例來幫助讀者更好地理解。 1.模運算子的作用在數學中,當我們將一個整數除以另一個整數時,就會得到一個商和一個餘數。例如,當我們將10除以3時,商數為3,餘數為1。模運算子就是用來取得這個餘數的。 2.模運算子的用法在PHP中,使用%符號來表示模

js和vue的關係 js和vue的關係 Mar 11, 2024 pm 05:21 PM

js和vue的關係:1、JS作為Web開發基石;2、Vue.js作為前端框架的崛起;3、JS與Vue的互補關係;4、JS與Vue的實踐應用。

Linux的curl指令詳解 Linux的curl指令詳解 Feb 21, 2024 pm 10:33 PM

Linux的curl命令詳解摘要:curl是一種強大的命令列工具,用於與伺服器進行資料通訊。本文將介紹curl指令的基本用法,並提供實際的程式碼範例,幫助讀者更好地理解和應用該指令。一、curl是什麼? curl是命令列工具,用於發送和接收各種網路請求。它支援多種協議,如HTTP、FTP、TELNET等,並提供了豐富的功能,如檔案上傳、檔案下載、資料傳輸、代

深入了解Promise.resolve() 深入了解Promise.resolve() Feb 18, 2024 pm 07:13 PM

Promise.resolve()詳解,需要具體程式碼範例Promise是JavaScript中一種用來處理非同步操作的機制。在實際開發中,常常需要處理一些需要依序執行的非同步任務,而Promise.resolve()方法就是用來傳回一個已經Fulfilled狀態的Promise物件。 Promise.resolve()是Promise類別的靜態方法,它接受一個

See all articles