1. 程式人生 > >js在html中的載入執行順序

js在html中的載入執行順序

javaScript檔案(下面簡稱指令碼檔案)需要被HTML檔案引用才能在瀏覽器中執行。在HTML檔案中可以通過不同的方式來引用指令碼檔案,我們需要關注的是,這些方式的具體實現和這些方式可能會帶來的效能問題。

當瀏覽器遇到(內嵌)<script>標籤時,當前瀏覽器無從獲知javaScript是否會修改頁面內容。因此,這時瀏覽器會停止處理頁面,先執行javaScript程式碼,然後再繼續解析和渲染頁面。同樣的情況也發生在使用 src 屬性加在javaScript的過程中(即外鏈 javaScript),瀏覽器必須先花時間下載外鏈檔案中的程式碼,然後解析並執行它。在這個過程中,頁面渲染和使用者互動完全被阻塞了。

也就是說:每當瀏覽器解析到<script>標籤(無論內嵌還是外鏈)時,瀏覽器會(一根筋地)優先下載、解析並執行該標籤中的javaScript程式碼,而阻塞了其後所有頁面內容的下載和渲染。

五種引用指令碼的方式:

1.慣例的做法

2.經典的做法

3.動態指令碼

4.LABjs

5.requireJS

==慣例的做法

最傳統的方式是在head標籤內插入<script>標籤:

然而這種常規的做法卻隱藏著嚴重的效能問題。根據上述對<script>標籤特性的描述,我們知道,在該示例中,當瀏覽器解析到<script>標籤時,瀏覽器會停止解析其後的內容,而優先下載指令碼檔案,並執行其中的程式碼,這意味著,其後的test.css樣式檔案和<body>標籤都無法被載入,由於<body>標籤無法被載入,那麼頁面自然就無法渲染了。因此在該javaScript程式碼完全執行完之前,頁面都是一片空白。

<script type="text/javaScript" src="example.js"></script>

==經典的做法

既然<script>標籤會阻塞其後內容的載入,那麼將<script>標籤放到所有頁面內容之後不就可以避免這種糟糕的狀況了嗎? 將所有的<script>標籤儘可能地放到<body>標籤底部,以儘量避免對頁面其餘部分下載的影響。

然在IE8+瀏覽器上已經實現了指令碼並行下載,但在某些瀏覽器中(即使指令碼檔案放到了<body>標籤底部),頁面中指令碼仍是一個接著一個載入的。所以我們需要下一個方法,即:動態載入指令碼

==動態指令碼

通過文件物件模型(DOM),我們可以幾乎可以頁面任意地方建立

var script=document.createElement(‘script’); 
script.type=’text/javaScript’; 
script.src=’file1.js’; 
document.getElementsByTagName(‘head’)[0].appendChild(script); 

上述程式碼動態建立了一個外鏈file1的<script>標籤,並將其新增到<head>標籤內。這種技術的重點在於:

無論在何時啟動下載,檔案的下載和執行過程不會阻塞頁面其他程序(包括指令碼載入)。

然而這種方法也是有缺陷的。這種方法載入的指令碼會在下載完成後立即執行,那麼意味著多個指令碼之間的執行順序是無法保證的(除了Firefox和Opera)。當某個指令碼對另一個指令碼有依賴關係時,就很可能發生錯誤了。比如,寫一個jQuery程式碼,需要引入jQuery庫,然而你寫的jQuery程式碼檔案很可能會先完成下載並立即執行,這時瀏覽器會報錯——‘jQuery未定義’之類的,因為此時jQuery庫還未下載完成。於是做出以下改進:

function loadScript(url,callback){
var script=document.createElement(‘script’);
script.type=”text/javaScript”;
if(script.readyState){//IE
 script.onreadystatechange=function(){ 
if(script.readyState==”loaded”||script.readyState==”complete”){ 
script.onreadystatechange=null; callback(); } };
}else{//其他瀏覽器
 script.onload=function(){ callback(); }; } script.src=url; 
document.getElementsByTagName(‘head’)[0].appendChild(script);
 }

上述程式碼改進的地方就是增加了一個回撥函式,該函式會在相應指令碼檔案載入完成後被呼叫。這樣便可以實現順序載入了,寫法如下(假設file2依賴file1,file1和file3相互獨立):

loadScript(‘file1.js’,function(){ loadScript(‘file2.js’,function(){}); }); loadScript(‘file3.js’,function(){}); 

file2會在file1載入完後才開始載入,保證了在file2執行前file1已經準備妥當。而file1和file3是並行下載的,互不影響。 雖然loadScript函式已經足夠好,但還是有些不盡人意的地方——通過分析這段程式碼,我們知道,loadScript函式中的順序載入是以指令碼的阻塞載入來實現的(正如上述紅字部分指出的那樣)。而我們真正想實現的是——指令碼同步下載並按相應順序執行,即並行載入並順序執行。

==LABjs

LABjs庫能幫我們真正地實現“並行載入與順序執行”,推薦寫法如下:

<script src="LAB.js"></script>
  <script type="text/javaScript">
    $LAB
     .script("script1.js").wait()
     .script("script2-a.js")
     .script("script2-b.js")
     .wait(function(){
       initScript1();
       initScript2();
     })
     .script("script3.js")
     .wait(function(){
       initScript3();
     });
  </script>

==requireJS

<script src="require.js"></script>
  <script type="text/javaScript">
    require([
      "script1.js",
      "script2-a.js",
      "script2-b.js",
      "script3.js"
     ],
     function(){
      initScript1();
      initScript2();
      initScript3();
     }
    );
  </script>

相關推薦

js在html載入執行順序

javaScript檔案(下面簡稱指令碼檔案)需要被HTML檔案引用才能在瀏覽器中執行。在HTML檔案中可以通過不同的方式來引用指令碼檔案,我們需要關注的是,這些方式的具體實現和這些方式可能會帶來的效能問題。 當瀏覽器遇到(內嵌)<script>標籤時,當前

Spring框架InitializingBean執行順序

ans .com 構造函數 tar start bean 復制代碼 init auth 本文轉自:https://www.cnblogs.com/yql1986/p/4084888.html package org.test.InitializingBean; 2

JavaScript在頁面執行順序(理解聲明式函數與賦值式函數) 轉載

AD TE 我們 行動 first FN 順序 而且 編譯性語言 JavaScript在頁面中的執行順序 https://blog.csdn.net/superhoy/article/details/52946277 2016年10月27日 15:38:52 閱讀數:

Java 基礎:繼承執行順序

類的方法 主程 rgs 這一 over print 類繼承 方法 www. 1.單獨的父類測試 Java中,new一個類的對象,類裏面的靜態代碼塊、非靜態代碼、無參構造方法、有參構造方法、類的一般方法等部分, 它們的執行順序相對來說比較簡單,用程序也很容易驗證。 比如

【分析】淺談C#Control的Invoke與BeginInvoke在主副線程執行順序和區別(SamWang)

info start result 初步 總結 inter blank rap 傳遞   今天無意中看到有關Invoke和BeginInvoke的一些資料,不太清楚它們之間的區別。所以花了點時間研究了下。   據msdn中介紹,它們最大的區別就是BeginInvoke屬於

多個css檔案在同一個html執行順序2

1、檔案位置在head裡面引入,無 !important 時  或 檔案位置在body裡面引入,無 !important 時        按照從上到下的順序依次執行,同一樣式會選擇最後一個檔案裡面的渲染[就近原則]。  

程式碼執行順序 及 組合

一  類的名稱空間:   類中的程式碼在什麼時候執行的?  在例項化之前,也就是說在建立一個類時,類自己先給自己建立 建一塊空間,也就是公共的空間.(裡面會把靜態變數和__init__及方法方進去) 類中程式碼執行順序:(在例項化之前就執行了) 問題:一個類中可不可以沒有__i

DQL執行順序詳解

引言 這不是一個什麼多深的技術問題,多麼牛叉的程式設計能力。這跟一個人的開發能力也沒有非常必然的直接關係,但是知道這些會對你的SQL編寫,排憂及優化上會有很大的幫助。它不是一個複雜的知識點,但是一個非常基礎的SQL根基。不瞭解這些,你一直用普通水泥蓋

一.js高階(6)-閉包-定時器-js程式碼執行順序

閉包1:巢狀的兩個作用域中 內層作用域訪問外層作用域 區域性變數的 過程 閉包2 :  就是能夠訪問其他函式內部變數的函式;     由於js中只有函式內部的子函式才能訪問區域性變數,所以可以簡單的把閉包理解為"定義在哈拿書內部的函式";     本質上閉包就是連線函式內部和外部的一座橋樑;

reactnative父子元件component執行順序

test1.js import React, { Component } from 'react'; import { View, } from 'react-native'; import Test2 from "./Test2"; export

java 繼承程式碼執行順序(個人見解)

面試題 以下程式碼執行結果 public class Test { class Super{ int flag=1; Super(){ test(); } void test(){

finally在try和catch塊以及return執行順序

執行順序 無catch時 finally會在try包含的return之後執行,會在try外面的return之前執行 當有catch時 finally是在catch執行之後catch包含的return之前執行的 執行順序圖

web-fragment 執行順序

最近在一個decouple的專案中引入了web-fragment.xml,  遇到了一些問題,比較好玩,記錄下。 web-fragment.xml 是servlet 3.0 以後引入的,它也是用來提供web部署描述的,功能上跟web.xml是一模一樣的。不一樣的地方是web-fragme

tensorflow更新引數順序與tf.group操作執行順序

想手動實現Adagrad,因為Adagrad有兩部分需要更新,因為之前合併兩個initializer用過tf.group,想當然認為tf.group可能是帶順序的,所以打算把兩個update直接group起來執行,看起來省事,感覺卻會出事,覺得很可能不帶順序,所以寫了個小de

[小Tip]IE9focus執行順序差異

提醒:本文最後更新於 2375 天前,文中所描述的資訊可能已發生改變,請謹慎使用。 以下程式碼,點test2後,firefox、chrome、opera輸出順序是1、2,但IE9的順序卻是2、1。 <input id="test1" /> <button id="test2">

servlet在spring載入順序

<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.sprin

Linux 常用環境變數及作用和環境變數檔案的詳細介紹及其載入執行順序

前言: 1. 環境變數是作業系統環境設定的變數,適用於整個系統的使用者程序; 2. 環境變數可以在命令中設定,但是使用者登出的時候將會丟失這些設定值; 3. 若要重複適用,則最好在.profile中

MySQL邏輯架構、SQL載入執行順序、七種JOIN模式圖解

邏輯架構 儲存引擎 檢視當前安裝的mysql提供的儲存引擎 檢視當前mysql預設的儲存引擎 MyISAM和InnoDB SQL載入執行

靜態程式碼塊,構造程式碼塊,構造方法的載入執行順序研究

構造程式碼塊是給所有的物件進行初始化,也就是說,所有的物件都會呼叫同一個程式碼塊。只要物件一創立,就會呼叫這個程式碼塊。 package com.inphase.construct; public class Demo {     private static int

Java類程式碼執行順序

先上程式碼: 1.程式碼片段一: /** * @author szn25 */ public class Main { static { System.out.println("main.static!"); } public static int fun