在前端開發中,JavaScript 檔案的引入方式直接影響頁面載入效能與腳本執行順序。本文將系統性梳理各種引用方法的同步與非同步特性,並透過實測代碼驗證瀏覽器行為差異,幫助開發者做出最佳選擇。
<script> // 同步載入執行的代碼 </script>
瀏覽器解析到此處會立即執行,阻塞後續 DOM 解析與渲染。
<script src="xx.js"></script> // 同步載入執行 xx.js 中的代碼
下載、解析、執行全過程阻塞主線程,按文檔順序依序執行。
<script>
document.write('<script src="xx.js"><\/script>');
// 非同步載入執行 xx.js 中的代碼
</script>
document.write 會將腳本注入文檔流,但瀏覽器不保證立即執行,屬非同步行為。
<script src="xx.js"></script>
// xx.js 內容:
document.write('<script src="11.js"><\/script>');
document.write('<script src="22.js"><\/script>');
此時 11.js、22.js 會同步載入並按順序執行。若 xx.js 本身以非同步方式載入,內部鏈仍保持同步特性(即「非同步中的同步」)。
var script = document.createElement("script");
script.setAttribute("src", "xx.js");
document.getElementsByTagName("head")[0].appendChild(script);
此為主流非阻塞載入模式,需配合 onload/onreadystatechange 實現回調。
var loadJS = function(url, callback) {
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.src = url;
script.type = "text/javascript";
head.appendChild(script);
script.onload = script.onreadystatechange = function() {
// IE 下有 onreadystatechange,W3C 標準有 onload
// readyState 针对 IE8 及以下
if ((!this.readyState) || this.readyState === "complete" || this.readyState === "loaded") {
callback();
} else {
alert("can not load the js file");
}
};
};
測試環境:tryjs.html 主頁 → tryjs.js(document.write 引入 try.1.js、try.2.js)
outer js callback loading IE outer js callback loaded IE write begin write finished outer js callback complete IE file 1 callback loading IE file 2 callback loading IE loadjs 1 begin loadjs 1 finished loadjs 2 begin loadjs 2 finished file 2 callback complete IE file 1 callback complete IE
write begin write finished outer js callback complete IE file 1 callback loading IE file 2 callback loading IE loadjs 1 begin loadjs 1 finished loadjs 2 begin loadjs 2 finished file 1 callback complete IE file 2 callback complete IE
write begin write finished outer js callback, not IE loadjs 1 begin loadjs 1 finished file 1 callback, NOT IE loadjs 2 begin loadjs 2 finished file 2 callback, NOT IE
<script src="..." defer> 延遲執行(保持順序)async 並行載入(不保證順序)理解 JavaScript 載入機制的同步/非同步特性,是優化首屏渲染、避免阻塞、解決依賴競態的基礎。現代開發應拥抱 defer/async 與 ES Modules,逐步淘汰 document.write 等歷史遺留模式。