解决Jquery、Bootstrap渲染阻塞及动态加载JS依赖顺序问题
解决脚本渲染阻塞与依赖加载顺序问题
首先,咱们先搞清楚你当前代码出问题的核心原因:你现在是一次性把所有脚本标签添加到页面中,浏览器会并行下载这些脚本文件,而且执行顺序不一定严格按照你数组里的顺序(尤其是不同脚本的下载速度不同时)。这就导致依赖jQuery的脚本(比如Bootstrap、utility.min.js这些)可能在jQuery还没加载执行完成时就先跑起来了,自然会报jQuery is not defined这类错误。
要解决这个问题,核心是要保证脚本按顺序加载并执行——也就是先完全加载并执行jQuery,再加载Bootstrap,接着再加载后续依赖它们的脚本。下面给你两种可行的方案:
方案1:递归式顺序加载(兼容旧浏览器)
这个方案用递归的方式,每次只加载一个脚本,等当前脚本加载完成后再加载下一个,完美保证依赖顺序:
var sources = [ "common/scripts/external/jquery-3.2.1.min.js", "common/scripts/external/bootstrap.min.js", "common/scripts/other/utility.min.js?v=1.0.0", "common/scripts/external/jquery.ui.widget.min.js", "common/scripts/external/jquery.fileupload.min.js", "common/scripts/external/jquery.fileupload-process.min.js", "common/scripts/external/jquery.fileupload-validate.min.js", "common/scripts/external/jquery.knob.min.js", "common/scripts/external/jquery.payform.min.js" ]; // 递归加载脚本,index为当前要加载的脚本下标 function loadScript(index) { // 所有脚本加载完成,终止递归 if (index >= sources.length) return; var scriptElement = document.createElement("script"); scriptElement.src = sources[index]; // 当前脚本加载完成后,加载下一个 scriptElement.onload = function() { loadScript(index + 1); }; // 可选:处理脚本加载失败的情况 scriptElement.onerror = function() { console.error(`加载脚本失败:${sources[index]}`); loadScript(index + 1); // 可根据需求调整,比如失败后停止加载 }; document.body.appendChild(scriptElement); } // 页面加载完成后启动加载流程 if (window.addEventListener) { window.addEventListener("load", function() { loadScript(0); }, false); } else if (window.attachEvent) { window.attachEvent("onload", function() { loadScript(0); }); } else { window.onload = function() { loadScript(0); }; }
方案2:Promise链式加载(现代浏览器友好)
如果你不需要兼容特别老旧的浏览器,用Promise来实现顺序加载会更清晰,还能方便处理整体加载成功/失败的情况:
var sources = [ "common/scripts/external/jquery-3.2.1.min.js", "common/scripts/external/bootstrap.min.js", "common/scripts/other/utility.min.js?v=1.0.0", "common/scripts/external/jquery.ui.widget.min.js", "common/scripts/external/jquery.fileupload.min.js", "common/scripts/external/jquery.fileupload-process.min.js", "common/scripts/external/jquery.fileupload-validate.min.js", "common/scripts/external/jquery.knob.min.js", "common/scripts/external/jquery.payform.min.js" ]; // 封装单个脚本加载为Promise function loadSingleScript(src) { return new Promise(function(resolve, reject) { var script = document.createElement('script'); script.src = src; script.onload = resolve; script.onerror = reject; document.body.appendChild(script); }); } // 按顺序加载所有脚本 function loadScriptsInOrder(scriptList) { return scriptList.reduce(function(prevPromise, currentSrc) { return prevPromise.then(function() { return loadSingleScript(currentSrc); }); }, Promise.resolve()); } // 页面加载完成后启动加载 if (window.addEventListener) { window.addEventListener("load", function() { loadScriptsInOrder(sources) .then(function() { console.log("所有脚本加载完成!"); }) .catch(function(error) { console.error("脚本加载出错:", error); }); }, false); } else if (window.attachEvent) { window.attachEvent("onload", function() { loadScriptsInOrder(sources) .then(function() { console.log("所有脚本加载完成!"); }) .catch(function(error) { console.error("脚本加载出错:", error); }); }); } else { window.onload = function() { loadScriptsInOrder(sources) .then(function() { console.log("所有脚本加载完成!"); }) .catch(function(error) { console.error("脚本加载出错:", error); }); }; }
额外优化建议
- 如果你想更早开始加载脚本,不用等页面所有资源(比如图片)加载完成,可以把
window.load事件换成DOMContentLoaded事件——这个事件会在页面DOM结构构建完成后就触发,能提前启动脚本加载,提升用户体验。 - 如果你后续考虑合并脚本,把jQuery、Bootstrap和依赖它们的脚本打包成一个文件,也能从根本上解决顺序问题,同时减少HTTP请求数,进一步优化加载速度。
内容的提问来源于stack exchange,提问作者OM The Eternity
相关产品推荐
相关产品推荐

