1. 程式人生 > >Script標籤和指令碼執行順序

Script標籤和指令碼執行順序

0.前言

估計所有讀者也慢慢適應我每次講東西之前先墨跡一段的習慣了。

那麼我今天就來個轉換,我!不!墨!跡!了!

正文開始。

1.script標籤的預設行為

首先我們先來看一下 <script> 標籤 的幾個重要特性:

  • script標籤的會阻止文件渲染。相關指令碼會立即下載並執行。
    注意:(不帶deferasync屬性)
  • document.currentScript 可以獲得當前正在執行的指令碼(Chrome 29+, FF4+)。
  • 指令碼順序再預設情況下和script標籤出現的順序一致。

既然我們已經明確了 script 標籤的基本特性。

那我們就先來看一個例子,用這個例子來說明 script 的載入順序問題。

2. script 的載入順序

假設如下簡單程式碼,我們去看一下,執行的結果是什麼樣子?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>李鵬:3206064928</title>
</head>
<body>

</body>
    <script>alert("MR_LP : A");</script>
    <script>alert("MR_LP : B"
);
</script> <script>alert("MR_LP : C");</script> </html>

執行結果如下:

這是我們按照正常的邏輯去執行,分別彈出了 :

  1. MR_LP : A
  2. MR_LP : B
  3. MR_LP : C

那我們再去考慮一下,在有網路的情況,請求的順序會怎樣呢?

在這裡我去做一個限制,將我們的第二個檔案中,書寫非常多的註釋,讓我們的第二個檔案大小要遠遠大於另外兩個檔案。

這時候我們再去看一下,順序是什麼樣子的。

結果如何呢?

你會發現我們的載入順序和上面一模一樣。

這是為什麼呢?第二個檔案明明要大於另外兩個檔案呀。

這裡就要說到 script標籤 的柱塞式執行方式了。

3. script 標籤的屬性

在說上面的問題之前,咱們先回顧一下,script 標籤 的六個屬性。

屬性名 介紹
1 type
2 src
3 charset
4 language
5 async
6 defer

注意:
雖然text/javascript 和text/ecmascript 都已經不被推薦使用,
但人們一直以來使用的都還是text/javascript。
實際上,服務端在傳送JavaScript 檔案時使用的 MIME 型別通常是application/x-javascript,
但在type中設定這個值卻可能導致指令碼被忽略。
另外,在非IE瀏覽器中
還可以使用以下值:application/javascript 和application/ecmascript。
考慮到約定成俗和最大限度的瀏覽器相容性,
目前type 屬性的值依舊還是text/javascript。

除此之外,屬性 1 ~ 4 是 HTML4.01中定義的,而 5 和 6 則是 HTML 5 中新增的內容,那我們接下來就專門針對這兩個新屬性,來看一下,script 的柱塞式執行

4.async屬性

async屬性是HTML5的新特性,這意味著其相容性並不樂觀(IE10+)。

async表示該script標籤並不柱塞,也不同步執行。

瀏覽器只需要在指令碼下載完畢後再執行即可——不必柱塞頁面渲染等待該指令碼的下載和執行。

如下程式碼[^4],會得到三個alert,但是alert的內容分別是”A”,”C”,”B”。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>李鵬:3206064928</title>
</head>
<body></body>
<script  src="https://snipt.net/raw/7b08744009c450e07c0bfc1d606fc72e/"></script>
<script  src="https://snipt.net/raw/a2e8c05c1f6fc0e47d259aa899304e89/" async="async"></script>
<script  src="https://snipt.net/raw/4fab3017d3d46cbfc4bbd88aab006650/"></script>
</html>

執行結果如下:

可以看到,第二個script標籤在加入async後,並沒有阻止後續文件解析和指令碼執行。

考究這個屬性產生的原有,其實有大量的指令碼載入器在做這樣的事情:

var script = document.createElement("script");
script.src = "file.js";
document.body.appendChild(script);

那麼我們不難想象,通過指令碼非同步插入的script標籤達到的效果和帶async屬性的script標籤是一樣的。

換句話說,由指令碼插入的script標籤預設是async的。

另外,對內聯指令碼設定async屬性是沒有意義的,也不產生其他效果。

其包含的指令碼總是立即執行的。

5. defer屬性

帶有defer屬性的指令碼,同樣會推遲指令碼的執行,並且不會阻止文件解析。

就如同這個指令碼,放置到了文件的末尾(</body>之前)。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>李鵬:3206064928</title>
</head>
<body></body>
<script  src="https://snipt.net/raw/7b08744009c450e07c0bfc1d606fc72e/"></script>
<script  src="https://snipt.net/raw/a2e8c05c1f6fc0e47d259aa899304e89/" defer="defer"></script>
<script  src="https://snipt.net/raw/4fab3017d3d46cbfc4bbd88aab006650/"></script>
</html>

上面的程式碼的巨集觀現象和加了async屬性的例子是一樣的,都是會得到”A”、”C”、”B”的三個alert。

但是其原理是不一樣的。

defer屬性是會確保指令碼在文件解析完畢後執行的。

即使這個指令碼在文件解析過程中就已經下載完畢變成可執行的狀態,

瀏覽器也會推遲這個指令碼的執行,直到文件解析完畢,並在DOMContentLoaded之前。

同時,帶有defer的指令碼彼此之間,能保證其執行順序。

注意,defer屬性並不是每個瀏覽器支援,

即便支援的瀏覽器,也會因為版本不一樣導致具體行為不一致。

另外,大家可以通過將script標籤放置到文件末尾這種簡單的做法達到defer屬性一樣的效果。

defer屬性早在IE4就被支援,但是這個defer屬性和現代瀏覽器的行為是有區別的。

只有IE10以上,才開始按照標準執行defer屬性。

6. async與defer的影響

參考W3C的官方文件,defer和async兩個屬性是可以互相影響的:

There are three possible modes that can be selected using these attributes. If the async attribute is present, then the script will be executed asynchronously, as soon as it is available. If the async attribute is not present but the defer attribute is present, then the script is executed when the page has finished parsing. If neither attribute is present, then the script is fetched and executed immediately, before the user agent continues parsing the page.

簡單的歸納:

  • 僅有async屬性,指令碼會非同步執行
  • 僅有defer屬性,指令碼會在文件解析完畢後執行
  • 兩個屬性都沒有,指令碼會被同步下載並執行,期間會柱塞文件解析

規範裡沒有提到兩種屬性都有時的效果,但這是文件中被允許的。

這樣的具體效果會在後面討論。

7. document.write的影響

docuemnt.write允許向開啟的文件流中寫入文件內容;

內嵌到HTML裡面的docuemnt.write可以就地新增文件內容。

考慮到docuemnt.write寫入script標籤的情況:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>李鵬:3206064928</title>
</head>
<body></body>
<script  src="https://snipt.net/raw/7b08744009c450e07c0bfc1d606fc72e/"></script>
<script>document.write("\<script  src=https://snipt.net/raw/a2e8c05c1f6fc0e47d259aa899304e89 \/\>\<\/script\>");</script>
<script  src="https://snipt.net/raw/4fab3017d3d46cbfc4bbd88aab006650/"></script>
</html>

執行結果如下:

我們觀察到執行順序和普通的script標籤沒有區別。

即使你插入的標籤帶有async或defer,其行為也是沒有區別的。

讓人糾結的是反過來使用。

將我們的 document.write 寫在頁面中時,其餘載入按照正常順序。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>李鵬:3206064928</title>
</head>
<body></body>
<script src="https://snipt.net/raw/7b08744009c450e07c0bfc1d606fc72e/"></script>
<script src="https://snipt.net/raw/773d794c9051a238e5c102e65dbaa2e9/"></script>
<script src="https://snipt.net/raw/4fab3017d3d46cbfc4bbd88aab006650/"></script>
</html>

載入結果如下:

由於第二個指令碼是通過document.write寫入的。

被延遲的指令碼在執行時,document已經關閉,document.write是沒有任何效果的。

所以,不管使用defer還是async,第二個指令碼始終沒有執行。

相關推薦

Script標籤指令碼執行順序

0.前言 估計所有讀者也慢慢適應我每次講東西之前先墨跡一段的習慣了。 那麼我今天就來個轉換,我!不!墨!跡!了! 正文開始。 1.script標籤的預設行為 首先我們先來看一下 <script> 標籤 的幾個重要特性: scri

一個頁面有多個script標籤時,執行順序

JavaScript直譯器在執行指令碼時,是按塊執行的。通俗地說,就是瀏覽器在解析HTML文件流時,如果遇到一個script標籤,則JavaScript直譯器會等到這個程式碼塊都載入完成後,先對程式碼塊進行預編譯,然後再執行。執行完畢後,瀏覽器會繼續解析下面的HTML文件流,同時JavaSc

unity 指令碼執行順序設定 Script Execution Order Settings

 通過Edit->Project Settings->Script Execution Order開啟MonoManager面板  或者選擇任意指令碼在Inspector檢視中點選Exe

從矩陣乘法來看-O優化ijk執行順序對程式效能的影響

從矩陣乘法來看-O優化和ijk執行順序對程式效能的影響 根據計算矩陣乘積的c程式,主要想做想做兩件事情: 統計採用不同的優化選項編譯程式所用的時間,感受-O優化帶來的效能提升。 看看矩陣乘法中不同迴圈順序對程式效能的影響: 改變三重迴圈的順序,統

printf()scanf()執行順序

原始碼:void main(){int a,b,c,x2,y2;printf("輸入a,b,c:\n");scanf("%d%d%d",&a,&b,&c);result(a,b,c,&x2,&y2);test(a,b,c,x2,y2);

spring [email protected]bean執行順序問題

從配置檔案中獲取配置使用@value,當你在bean載入時呼叫@value時會出現空指標異常。因為bean載入完成後才會執行@value。    解決辦法:spring boot 有兩種獲取配置檔案值的方式 第一種,@value(“${a.b}”)傳屬性名稱 第二種:使

JS事件機制:事件繫結、事件監聽、事件委託(代理)事件執行順序總結

JS 對於使用者的操作做出響應,就必須對DOM元素繫結事件處理函式 事件繫結  1、在DMO中直接繫結事件 <input type="button" value="click me"

servlet filter執行順序

在我們寫程式碼時,在web.xml中總能發現類似下面的程式碼: <spanstyle="font-family:KaiTi_GB2312;font-size:18px;"><spanstyle="font-family:KaiTi_GB2312;

SQL語句中的ANDOR執行順序問題

情景:一個搜尋框 可以同時根據使用者賬號或者使用者名稱字 搜尋匹配條件的使用者 如果搜尋框中沒有搜尋條件 則查出所有教師使用者 遇到的問題: 查詢條件時為輸入框內的內容 先在資料庫中模擬測試 結果

同一個頁面,多個script標籤中Javascript執行問題

<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head>

Linux啟動指令碼執行順序

1.一般核心啟動後。 ①先識別儲存器分割槽,根據root=/dev/block/mtd/mmcblk0p6這樣的的引數掛載檔案系統 ②執行檔案系統中的init=/sbin/init執行啟動指令碼 ③一般這個時候指令碼中可能會有分割槽識別指令碼,將分

從join onwhere執行順序認識T-SQL查詢處理執行順序

SQL語句中join連表時on和where後都可以跟條件,那麼對查詢結果集,執行順序,效率是如何呢? 通過查詢資料發現:區別:on是對中間結果進行篩選,where是對最終結果篩選。執行順序:先進行on的過濾, 而後才進行join。效率:如果是inner join, 放o

JSCSS執行順序

一、指令碼和樣式表載入、執行順序總結1、指令碼web的模式是同步的,開發者希望解析到一個script標籤時立即解析執行指令碼,並阻塞文件的解析直到指令碼執行完。如果指令碼是外引的,則網路必須先請求到這個資源——這個過程也是同步的,會阻塞文件的解析直到資源被請求到。這個模式保持了很多年,並且在html4及htm

淺談Unity的指令碼執行順序

一、新增指令碼的順序 這是一張官方的指令碼順序圖   一般,當我們把指令碼繫結在遊戲物件上時,或者點選繫結好的指令碼的reset按鈕時,會呼叫Reset() 當我們初始化一個物件時,會先呼叫Awake()在呼叫OnEnable() GameObject.instantiate(o); star

標籤href屬性onclick()執行順序及點選兩次才跳轉

今天寫一個小demo時,發現正常點選連結不跳轉,只有連續點選兩次才會跳轉,程式碼很簡單,如下: <a href="" onclick="queryStudent()">查詢</a>因為太簡單了,也因為知道onclick()的執行順序在href之前

JS中事件的執行順序AJAX的異步

容易 jquery 博客 出現問題 同步 內容 img 留言 加載 之前了解過異步和同步,知道同步是順序執行,異步是同時執行,但是沒有遇到過這種情況,不是很理解,這兩天做項目突然遇到了,對這有了一個初步的認識。廢話不多說,直接上要求。 1.項目要求:外部調用x

SQL語句的執行順序效率

繼續 col 最好的 rom where 需要 完整 nbsp 解析 今天上午在開發的過程中,突然遇到一個問題,需要了解SQL語句的執行順序才能繼續,上網上查了一下相關的資料,現整理如下:一、sql語句的執行步驟: 1)語法分析,分析語句的語法是否符合規範,衡量語句中各表達

主線程子線程執行順序問題

執行 他會 debug @override args stat 明顯 輸出 被調用 public class MyThread implements Runnable { @Override public void run() { Syst

【轉】【WPF】關於依賴屬性的ValidateValueCallback,PropertyChangedCallbackCoerceValueCallback的執行順序

value read ado args cep img 強制轉換 .cn clas 三個回調對應依賴屬性的驗證過程,改變過程和強制轉換過程。 class Dobj : DependencyObject { //依賴屬性包裝 public int MyPro

JMeter學習(三) 元件的作用域執行順序

關於 sse blank 原則 問題 element spa pan ons 轉載自 ==== jmeter學習(三)元件的作用域與執行順序 1.元件的作用域 JMeter中共有8類可被執行的元件(測試計劃與線程組不屬於元件),這些元件中,取樣器是典型的不與其它元件發生