等待动态加载的脚本

在我的页面正文中,我需要插入这段代码作为 AJAX 调用的结果:

    <p>Loading jQuery</p>
<script type='text/javascript' src='scripts/jquery/core/jquery-1.4.4.js'></script>
<p>Using jQuery</p>
<script type='text/javascript'>
$.ajax({
...
});
</script>

我不能使用 $.load(),因为文档已经加载,所以事件不会触发。

这样安全吗?如果没有,我如何确保 jquery 脚本在我自定义生成的代码执行之前已经加载。

114569 次浏览

很安全。从历史上看,<script>标记是完全阻塞的,因此在前者完成解析/执行之前不会遇到第二个 <script>标记。唯一的问题可能是“现代”浏览器倾向于异步加载脚本并延迟加载。因此,为了确保顺序正确,可以这样使用:

<p>Loading jQuery</p>
<script type='text/javascript' async=false defer=false src='scripts/jquery/core/jquery-1.4.4.js'></script>
<p>Using jQuery</p>
<script type='text/javascript'>
$.ajax({
...
});
</script>

但是,使用动态脚本标记插入可能是一个更好的主意,而不是将其作为 HTML 字符串推送到 DOM 中。都是一样的

var scr  = document.createElement('script'),
head = document.head || document.getElementsByTagName('head')[0];
scr.src = 'scripts/jquery/core/jquery-1.4.4.js';
scr.async = false; // optionally


head.insertBefore(scr, head.firstChild);

$.Ajax 和 $。载荷是一回事。都可以。如果你把 $。在页面上加载一个脚本标记,当加载时会触发,就像 $。Ajax ().

当你需要等待一个脚本启动然后再去做一些事情的时候,托马拉克说的有点道理。异步调用是个例外。Javascript 将发出一个 AJAX 调用,然后继续运行该脚本,当 AJAX 调用响应时,它将运行成功/失败,这取决于您告诉它做什么。

现在假设您希望您的 JS 等待返回,只需要一个调用,就可以非常容易地将所有内容包装到成功回调中,或者您可以用一种很酷的方式使用 $。延期。这允许您进行一系列 ajax 调用或一个调用,然后只在完成之后运行一些代码。

那么对于这种情况来说可能是最好的。

不管怎样,你现在做的都是安全的。

jQuery 1.6还有一个新特性。它叫做 jQuery.holdReady()。这实际上是不言而喻的; 当您调用 jQuery.holdReady(true)时,除非您调用 jQuery.holdReady(false),否则不会触发 ready事件。将此设置为 false 不会自动触发就绪事件,它只是删除了持有。

下面是从文档中加载脚本的非阻塞示例:

$.holdReady(true);
$.getScript("myplugin.js", function() {
$.holdReady(false);
});

有关更多信息,请参见 http://api.jquery.com/jQuery.holdReady/

将 ID 添加到脚本文件中,以便可以查询它。

<script id="hljs" async src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.0.0/highlight.min.js"></script>

然后在 JavaScript 中向其添加一个负载侦听器

<script>
var script = document.querySelector('#hljs');
script.addEventListener('load', function() {
hljs.initHighlightingOnLoad();
});
</script>

等待多个脚本加载

下面的帮助器只加载一次多个脚本并返回一个承诺:

async function cirosantilli_load_scripts(script_urls) {
function load(script_url) {
return new Promise(function(resolve, reject) {
if (cirosantilli_load_scripts.loaded.has(script_url)) {
resolve();
} else {
var script = document.createElement('script');
script.onload = resolve;
script.src = script_url
document.head.appendChild(script);
}
});
}
var promises = [];
for (const script_url of script_urls) {
promises.push(load(script_url));
}
await Promise.all(promises);
for (const script_url of script_urls) {
cirosantilli_load_scripts.loaded.add(script_url);
}
}
cirosantilli_load_scripts.loaded = new Set();


(async () => {
await cirosantilli_load_scripts([
'https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js',
]);


// Now do stuff with those scripts.


})();

GitHub 上游: 定义用途

测试是铬75。

const jsScript = document.createElement('script')
jsScript.src =
'https://coolJavascript.js'


document.body.appendChild(jsScript)


jsScript.addEventListener('load', () => {
doSomethingNow()
})

将在动态添加脚本之后加载

在我的情况下,解决方案不起作用。我希望在脚本加载了链接的右键单击事件之后以编程方式单击链接。因此,我必须使用超时和循环:

<script>
var ifrbutton = document.getElementById("id-of-link");
if(typeof(ifrbutton) != 'undefined' && ifrbutton != null && window.location.hash == "#special-hash") {
var i = 0;
// store the interval id to clear in future
var intr = setInterval(function() {
if (ifrbutton.onclick!=null) {
ifrbutton.click();
clearInterval(intr);
i = 200;
}
if (++i >= 200) clearInterval(intr);
}, 300)
}
</script>

因此,解决方案也可以是检查脚本带来的某些功能的时间间隔... 设置一些安全的结束,以防止脚本从未加载... 对我来说是安全的;)

    new MutationObserver((mutationsList, observer) => {
for (var mutation of mutationsList)
if (mutation.type === 'childList')
Array.from (mutation.addedNodes)
.filter (node => node.tagName === 'SCRIPT')
.forEach (script => {
//Script started loading
script.addEventListener ('load', () => {
//Script finished loading
})
})
}).observe(document, { attributes: false, childList: true, subtree: true });

这对我有用

function loadScript(sources, callBack) {
var script      = document.createElement('script');
script.src      = sources;
script.async    = false;
document.body.appendChild(script);
    

script.addEventListener('load', () => {
if(typeof callBack == "function") callBack(sources);
});
}