如何確保JavaScript的執行順序 之實戰篇

來源:互聯網
上載者:User

1. 引言
我曾在文章《如何在多個頁面使用同一個HTML片段 - 續》的最後提到JavaScript順序執行的特性。雖然現代瀏覽器可以並行的下載JavaScript(部分瀏覽器),但考慮到JavaScript的依賴關係,他們的執行依然是按照引入順序進行的。
為了更好的測試這個過程,我寫了一個簡單的HTTP處理常式頁面 service.ashx,它可以接受兩個參數:
1. file,需要返迴文件的伺服器端路徑。
2. delay,延遲一定時間後再返回本次HTTP請求(毫秒)。
一個典型的頁面比如:./service.ashx?file=js/jquery-ui.js&delay=2000,表示延遲2秒鐘後再返回伺服器端的js/jquery-ui.js檔案。
service.ashx 的關鍵代碼如下:
複製代碼 代碼如下:
public void ProcessRequest(HttpContext context)
{
int delay = 0;
if (!String.IsNullOrEmpty(context.Request["delay"]))
{
delay = Convert.ToInt32(context.Request["delay"]);
}
if (delay > 0)
{
System.Threading.Thread.Sleep(1000);
}
string filePath = context.Request["file"].ToString();
string fileContent = String.Empty;
using (StreamReader sr = new StreamReader(context.Server.MapPath(filePath)))
{
fileContent = sr.ReadToEnd();
}
if (filePath.EndsWith(".js"))
{
context.Response.ContentType = "application/x-javascript";
}
else
{
context.Response.ContentType = "text/plain";
}
context.Response.Write(fileContent);
}

2. 通過script標籤直接引入JavaScript(test1.htm)
首先我們分析下在<head>標籤中順序引入JavaScript的情況。test1.htm的頁面原始碼如下:
複製代碼 代碼如下:
<html>
<head>
<title></title>
<script src="./js/jquery-1.4.4.js"
type="text/javascript"></script>
<script src="./service.ashx?file=js/jquery-ui.js&delay=2000"
type="text/javascript"></script>
<script>
alert(typeof (jQuery.ui));
</script>
</head>
<body>
</body>
</html>

我們分別在各種瀏覽器中測試這個例子:
test1.htm
通過script標籤直接引入JavaScript

Firefox 3.6

IE 8

Chrome 10

Safari 4

Opera 11

 

可以看出各個主流瀏覽器的行為一致。雖然jQueryUI在伺服器延遲了2秒鐘再返回,但是後引入的內聯JavaScript還是等待了2秒,等前面引入的JavaScript執行完畢才執行。這也是著名的JavaScript順序執行的特性。
3. 通過JavaScript添加script標籤(test3.htm)
我們首先定義一個addScript函數,用來引入外部或者內聯JavaScript。test3.htm的頁面原始碼如下:
複製代碼 代碼如下:
<html>
<head>
<title></title>
<script src="./js/jquery-1.4.4.js" type="text/javascript"></script>
<script>
function addScript(url, inline) {
var head = document.getElementsByTagName("head")[0];
var script = document.createElement('script');
script.type = 'text/javascript';
if (inline) {
script.text = url;
} else {
script.src = url;
}
head.appendChild(script);
}
$(function () {
addScript('./service.ashx?file=js/jquery-ui.js&delay=2000');
addScript('alert(typeof(jQuery.ui));', true);
});
</script>
</head>
<body>
<div id="container">
</div>
</body>
</html>

我們分別在各種瀏覽器中測試這個例子:
test3.htm
通過JavaScript添加<script>標籤

Firefox 3.6

IE 8

Chrome 10

Safari 4

Opera 11

可見,通過JavaScript在DOM載入完畢後再引入外部或者內聯JavaScript時,Firefox和Opera的行為一致,能夠確保JavaScript的執行順序和引入順序一致。但是IE8, Chrome, Safari 卻不能保證這個執行順序。

雖然各種瀏覽器在確保執行順序方面不盡相同,不過這時的最大好處是多個JavaScript檔案能夠並行下載,這在所有瀏覽器中行為一致。當然這不是這篇文章的主題,可以Google更多細節。

如何解決各個瀏覽器的不一致性,下面提供了兩個解決方案:
4. 方案一,如何在動態添加script標籤時確保執行順序
有時頁面邏輯要求我們必須通過上面的方式動態執行JavaScript,那麼如何確保所有瀏覽器下的執行順序(目前只有Firefox和Opera確保執行順序)。
其實解決方案很簡單,我們為函數執行添加一個complete的回呼函數就行了。下面的test4.htm給出了具體的解決方案:
複製代碼 代碼如下:
<html>
<head>
<title></title>
<script src="./js/jquery-1.4.4.js" type="text/javascript"></script>
<script>
function addScript(url, inline, callback) {
var head = document.getElementsByTagName("head")[0];
var script = document.createElement('script');
script.type = 'text/javascript';
if (inline) {
script.text = url;
} else {
script.src = url;
script.onload = script.onreadystatechange = function () {
if (!script.readyState || script.readyState === 'loaded' || script.readyState === 'complete') {
if (callback) {
callback();
}
script.onload = script.onreadystatechange = null;
};
};
}
head.appendChild(script);
if (inline && callback) {
callback();
}
}
$(function () {
addScript('./service.ashx?file=js/jquery-ui.js&delay=2000', false, function () {
addScript('alert(typeof(jQuery.ui));', true);
});
});
</script>
</head>
<body>
<div id="container">
</div>
</body>
</html>

此時所有瀏覽器中的行為一致:
test4.htm
通過回呼函數解決動態添加JavaScript的順序問題

Firefox 3.6

IE 8

Chrome 10

Safari 4

Opera 11


5. 方案二,使用jQuery的html函數動態添加JavaScript
jQuery的html函數用來更新一個DOM片段,我們可以很方便的通過這個函數來動態載入JavaScript,請看樣本test2.htm:
複製代碼 代碼如下:
<html>
<head>
<title></title>
<script src="js/jquery-1.4.4.js" type="text/javascript"></script>
<script>
$(function(){
$('#container').html('<script src="./service.ashx?file=js/jquery-ui.js&delay=2000" type="text\/javascript"><\/script>' + '<script>alert(typeof(jQuery.ui));<\/script>');
});
</script>
</head>
<body>
<div id="container">
</div>
</body>
</html>

此時,各個瀏覽器中的行為一致:
test2.htm
通過jQuery的html函數解決動態添加JavaScript的順序問題

Firefox 3.6

IE 8

Chrome 10

Safari 4

Opera 11


6. 後記
為什麼jQuery的html函數能夠確保動態載入JavaScript的執行順序呢?
我們知道通過簡單的 .innerHTML 更新DOM節點,是不會讓其中的JavaScript的執行,我們可以簡單的把這個例子的原始碼改成:
$('#container')[0].innerHTML = '<script src="./service.ashx?file=js/jquery-ui.js&delay=2000" type="text\/javascript"><\/script>' + '<script>alert(typeof(jQuery.ui));<\/script>';
這種情況下jQueryUI根本不會載入。
那麼jQuery是如果做到的呢?下篇文章我們會追根溯源,詳細分析jQuery原始碼,請繼續瀏覽: 如何確保JavaScript的執行順序 – 之jQuery.html深度分析

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.