尝试在脚本标签上触发onload事件

143

我试图按顺序加载一组脚本,但是 onload 事件没有触发。

    var scripts = [
        '//cdnjs.cloudflare.com/ajax/libs/less.js/1.3.3/less.min.js',
        '//cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.0.0-rc.3/handlebars.min.js',
        MK.host+'/templates/templates.js'
    ];

    function loadScripts(scripts){
        var script = scripts.shift();
        var el = document.createElement('script');
        el.src = script;
        el.onload = function(script){
            console.log(script + ' loaded!');
            if (scripts.length) {
                loadScripts(scripts);
            }
            else {
                console.log('run app');
                MK.init();
            }
        };

        $body.append(el);
    }

    loadScripts(scripts);

我猜原生事件,比如 el.onload,在使用 jQuery 将元素添加到 DOM 时不会触发。如果我使用原生的 document.body.appendChild(el),则会按预期触发。


访问以下链接:https://dev59.com/S2445IYBdhLWcg3wdqIL这非常有用。 - Jitesh
3个回答

193

你应该在onload事件之后设置src属性,例如:

el.onload = function() { //...
el.src = script;

在附加 onload 事件之前,您还应该将脚本附加到 DOM 中:

$body.append(el);
el.onload = function() { //...
el.src = script;

请记住,您需要检查readystate以支持IE。如果您正在使用jQuery,您还可以尝试getScript()方法:http://api.jquery.com/jQuery.getScript/


14
实际上那并不能解决问题。但是如果我使用 document.body.appendChild(el) 而不是 $('body').append(el);,那么 onload 事件会如预期般触发。 - chovy
47
你能帮我理解为什么顺序很重要吗? - chovy
15
为什么不像 http://www.html5rocks.com/en/tutorials/speed/script-loading/ 中建议的那样最后添加元素?这样可以使添加事件监听器和设置 src 的顺序变得无关紧要。 - Stuart P. Bentley
9
为什么在设置“onload”和“src”属性之前将元素附加到DOM很重要? - Jake Wilson
13
如果脚本已被缓存,那么一旦您添加了"src"属性,该项目将被加载,"onload"事件就不会触发。在添加"src"之前添加"onload"事件将确保已缓存的脚本能够触发"onload"事件。 - JonShipman
显示剩余8条评论

13
我遇到了类似的问题,尝试测试页面上是否已经存在jQuery,如果不存在就强制加载并执行函数。我尝试使用@David Hellsing的解决方法,但对我的需求没有用处。事实上, onload 指令立即被评估,然后此函数内部的$使用还不可用(是的,那个丑陋的“$不是函数。”^^)。 因此,我参考了这篇文章:https://developer.mozilla.org/fr/docs/Web/Events/load ,并将事件监听器附加到我的脚本对象上。
var script = document.createElement('script');
script.type = "text/javascript";
script.addEventListener("load", function(event) {
    console.log("script loaded :)");
    onjqloaded(); // in fact, yourstuffscript() function
});
script.src = "https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js";
document.getElementsByTagName('head')[0].appendChild(script);

对于我的需求,它现在运行良好。希望这可以帮助其他人 :)


2
它在Chrome上无法工作,脚本已加载但事件未被触发。 - Firas Abd Alrahman

0

按顺序加载脚本的工作方式(即等待一个加载完成,然后加载另一个,依此类推...)

以下脚本已添加到 HTML 页面:

<script type="text/javascript">

    document.addEventListener("DOMContentLoaded", (event) => {

        function fn(src) {
            return new Promise(resolve => { // promise is initiated
                const script = document.createElement("script"); // creates <script> tag
                // script.async = true is not required since Promise is used
                script.onload = resolve; // promise will resolve on load event
                script.setAttribute("src", src); // will set srs="link to your source file here"
                document.getElementsByTagName('body')[0].appendChild(script); // append the created <script> tag to <body>
            });
        }

        const url = [ // order of script tags
            "/script1.js", 
            "/script2.js",
            "/script3.js"
        ];

        Promise.resolve(fn(url[0])) // wait until url[0] is resolved, then
            .then(() => fn(url[1])) // call and wait until url[1] is resolved, then
            .then(() => fn(url[2])) // call url[2]

    });

</script>

在每个".then"中使用"() =>"返回结果很重要。这称为链式调用

始终返回结果,否则回调函数将无法捕获前一个 promise 的结果(在箭头函数中,() => x 等同于 () => { return x; })

加载的 HTML 页面上的结果:

<body>
    <!-- your html -->
    <script src="/script1.js"></script>
    <script src="/script2.js"></script>
    <script src="/script3.js"></script>
</body>

chrome developer tools


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接