如何确定JavaScript(脚本)是否已加载?

5
我尝试编写一个JavaScript函数,用于加载js脚本( src ),当脚本加载完成时执行一些回调。同时我会检查是否存在具有相同 src 的脚本。
我的问题是,如果脚本已经加载,则不会执行回调函数。这是错误的。
如何知道脚本是否已经加载?
importScript: (function (head) {

    function loadError(error) {
        throw new URIError("The script " + 
                            error.target.src + " is not accessible.");}

    return function (url, callback) {
        var existingScript = document.querySelectorAll("script[src='" + 
                             url + "']");
        var isNewScript = (existingScript.length == 0);
        var script;
        if (isNewScript) {
            script = document.createElement("script")
            script.type = "text/javascript";
        }
        else {
            script = existingScript[0];
        }
        script.onerror = loadError;
        if (script.readyState) { //IE
            script.onreadystatechange = function () {
                if (script.readyState == "loaded" || 
                    script.readyState == "complete") {
                    script.onreadystatechange = null;
                    if (callback) {
                        callback(); }
                }
            };
        } else { // others than IE
            script.onload = callback; }

        if (isNewScript) {
            script.src = url;
            head.appendChild(script); }
    }
})(document.head || document.getElementsByTagName("head")[0])

据我所知,script.readyState == "loaded" || script.readyState == "complete" 只能在IE浏览器中使用,而在其他浏览器中并不适用...

用法:

importScript("myScript1.js");
importScript("myScript2.js", /* onload function: */ 
            function () { alert("The script has been OK loaded."); });

如果(isNewScript) {script.src = ...} else {callback(false);},并检查在callback中传递的参数以检测脚本是否已经加载? - Teemu
这个回答解决了你的问题吗?验证外部脚本是否已加载 - Frédéric
3个回答

9

我推荐使用jQuery,它非常易用。生命太短暂了,不要自己编写这样的代码(你将浪费数小时来支持所有浏览器)。

$.ajax({
  url: "/script.js",
  dataType: "script",
  success: function() {
    console.log("script loaded");
  }
});

编辑:
这个技巧更加简单易懂(来自jQuery文档的例子):

$.getScript( "ajax/test.js", function( data, textStatus, jqxhr ) {
  console.log(data); // Data returned
  console.log(textStatus); // Success
  console.log(jqxhr.status); // 200
});

您可以链接donefail来添加额外的回调函数:
$.getScript("ajax/test.js")
  .done(function(script, textStatus) {
    console.log(textStatus);
  })
  .fail(function(jqxhr, settings, exception) {
    console.log("loading script failed.");
  });

异步加载jQuery

<script src="path/to/jquery"></script>
<script>
function wait(method) {
    if (window.$) {
        method();
    } else {
        setTimeout(function () { wait(method); }, 100); // check every 100ms
    }
}

// wait for jQuery
wait(function() {
    // jQuery has loaded!
    $("#foo").doSomething();

    // you can now load other scripts with jQuery:
    $.getScript("ajax/test.js")
      .done(function(script, textStatus) {
        console.log(textStatus);
      })
      .fail(function(jqxhr, settings, exception) {
        console.log("loading script failed.");
      });
}
</script>

这是一个更好的解决方案。 - Y123
谢谢。我想知道如何检查脚本是否已加载,而不是如何加载脚本,因为我不确定jQuery此时是否已加载,所以我更喜欢使用纯JavaScript。 - serhio
请检查我的答案,我还添加了一些代码以异步加载jquery。 - Luca Steeb

1

最安全的检查脚本是否加载的方法是在脚本末尾添加一个简单的回调函数。如果存在,则可以调用该函数并传递一些数据。

if(window.loaded){
  window.loaded(params);
}

一旦脚本加载,它将执行此方法,您可以在父脚本中声明该方法,该方法将被调用。
此外,您可以在 body 上触发事件,并在其他父代码中侦听该事件。

非常方便:只需添加一个带有正确src的脚本标签,并在加载完成后通过回调启动。谢谢! - PhilMaGeo

0

基于 Luca Steeb 的方法,我将解决方案优化为只包含两个脚本标签,对于 SPA 应用程序而言,index.html 很紧凑:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Simplified INDEX</title>

    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script src="/bootloader.js"></script>
</head>

<body>
</body>

</html>

bootloader.js,结合了Luca和使用jquery加载css的想法

function loadScripts() {
  // jQuery has loaded!
  console.log("jquery is loaded");

  // you can now load other scripts and css files with jQuery:
  $.when($.getStylesheet('css/main.css'), $.getScript('js/main.js'))
    .then(function () {
       console.log('the css and js loaded successfully and are both ready');
    }, function () {
        console.log('an error occurred somewhere');
    });
}

function patchGetStylesheet($) {
  $.getStylesheet = function (href) {
    var $d = $.Deferred();
    var $link = $('<link/>', {
      rel: 'stylesheet',
      type: 'text/css',
      href: href
    }).appendTo('head');
    $d.resolve($link);
    return $d.promise();
  };
}

function wait(method) {
  if (window.$) {
    patchGetStylesheet(window.$);
    method();
  } else {
    setTimeout(function () {
      wait(method);
    }, 100); // check every 100ms
  }
}

// wait for jQuery
wait(loadScripts);

对于 bootloader.js,可以使用 webpack 进行缩小和混淆等处理。

通过使用 jQuery 解决运行时依赖关系后,我们将不再通过向 index.html 添加代码。


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