验证是否加载了外部脚本


79

我正在创建一个jQuery插件,我想验证是否加载了外部脚本。这是针对内部Web应用程序的,我可以保持脚本名称/位置一致(mysscript.js)。这也是一个ajaxy插件,可以在页面上多次调用。

如果可以验证脚本未加载,请使用以下命令加载脚本:

jQuery.getScript()

由于不想多次在页面上加载相同的脚本,如何验证脚本已加载?由于脚本缓存,这是我不需要担心的事情吗?

更新: 我可能无法控制谁在我们组织中使用此插件,并且可能无法强制使用或不使用特定ID的页面上没有该脚本,但脚本名称始终与同名。我希望可以使用脚本的名称来验证它是否已实际加载。


该线程位于SO jquery标签FAQ的顶部,并且具有用于检查是否存在脚本的大量方法stackoverflow.com/questions/1014203/…关于各种方法的大量反馈
charlietfl 2012年

Answers:


139

如果脚本在全局空间中创建了任何变量或函数,则可以检查其是否存在:

外部JS(在全球范围内)-

var myCustomFlag = true;

并检查是否已运行:

if (typeof window.myCustomFlag == 'undefined') {
    //the flag was not found, so the code has not run
    $.getScript('<external JS>');
}

更新资料

您可以<script>通过选择所有<script>元素并检查其src属性来检查标记是否存在:

//get the number of `<script>` elements that have the correct `src` attribute
var len = $('script').filter(function () {
    return ($(this).attr('src') == '<external JS>');
}).length;

//if there are no scripts that match, the load it
if (len === 0) {
    $.getScript('<external JS>');
}

或者,您可以直接.filter()在选择器中烘焙此功能:

var len = $('script[src="<external JS>"]').length;

这是一个很好的答案,不幸的是jquery.getScript方法添加了未指定源的脚本。因此我找不到它。我确实使用了部分答案来解决此问题,所以+1。
AGoodDisplayName 2012年

@AGoodDisplayName在回调中,$.getScript()您可以设置可以检查的全局标志:$.getScript('<external JS>, function () { window.myCustomFlag = true; }')。然后,您可以仅检查特定<script>元素或myCustomFlag变量的存在。
贾斯珀(Jasper)2012年

@jasper,是的,这可能是最有效的方法,这就是为什么我接受您的回答。将我的解决方案放进去(在其中应该包含一个全局标志)。
AGoodDisplayName 2012年

21
脚本src检查是可以的,但是问题是存在带有正确src的脚本标签并不意味着就已经加载了脚本。插入标签仅仅是加载阶段的开始。
卡罗尔2014年

3
@Jasper提出了一个问题,我认为可以通过将标记插入DOM来动态加载脚本。只有在您可以多次插入同一个脚本时(这是没人会在HTML中插入脚本,然后尝试再次动态加载)的唯一情况。因此,一旦插入脚本标记,您仍要等到它加载完毕,在这种情况下,您的答案将不起作用,因为它仅检查脚本标记是否存在。
卡罗尔2014年

18

@jasper的答案是完全正确的,但对于现代浏览器,标准的Javascript解决方案可能是:

function isScriptLoaded(src)
{
    return document.querySelector('script[src="' + src + '"]') ? true : false;
}

2
Boolean如果愿意,可以使用而不是有条件的运算符
某些性能

可能只是return document.querySelector('script[src="' + src + '"]');
Harshal Parekh

10

现在,由于我能找到解决方案的所有答案,因此我意识到了如何做到这一点非常简单。为了指定脚本的来源,我不得不放弃$ .getScript()……有时最好手动进行。

//great suggestion @Jasper
var len = $('script[src*="Javascript/MyScript.js"]').length; 

if (len === 0) {
        alert('script not loaded');

        loadScript('Javascript/MyScript.js');

        if ($('script[src*="Javascript/MyScript.js"]').length === 0) {
            alert('still not loaded');
        }
        else {
            alert('loaded now');
        }
    }
    else {
        alert('script loaded');
    }


function loadScript(scriptLocationAndName) {
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = scriptLocationAndName;
    head.appendChild(script);
}

8

关于这个问题的答案很少,但是我觉得值得添加这种解决方案。它结合了一些不同的答案。

对我来说关键点是

  • 添加#id标签,因此很容易找到,并且不会重复
  • 使用.onload()等到脚本完成加载后再使用

    mounted() {
      // First check if the script already exists on the dom
      // by searching for an id
      let id = 'googleMaps'
      if(document.getElementById(id) === null) {
        let script = document.createElement('script')
        script.setAttribute('src', 'https://maps.googleapis.com/maps/api/js?key=' + apiKey)
        script.setAttribute('id', id)
        document.body.appendChild(script) 
    
        // now wait for it to load...
        script.onload = () => {
            // script has loaded, you can now use it safely
            alert('thank me later')
            // ... do something with the newly loaded script
        }      
      }
    }
    

6

创建具有特定ID的脚本标签,然后检查该ID是否存在?

或者,循环遍历脚本标记以检查脚本“ src”,并确保这些标记尚未加载与要避免的标记相同的值?

编辑:以下反馈表明一个代码示例将是有用的:

(function(){
    var desiredSource = 'https://sitename.com/js/script.js';
    var scripts       = document.getElementsByTagName('script');
    var alreadyLoaded = false;

    if(scripts.length){
        for(var scriptIndex in scripts) {
            if(!alreadyLoaded && desiredSource === scripts[scriptIndex].src) {
                alreadyLoaded = true;
            }
        }
    }
    if(!alreadyLoaded){
        // Run your code in this block?
    }
})();

如评论(https://stackoverflow.com/users/1358777/alwin-kesler)所述,这可能是一种替代方法(未进行基准测试):

(function(){
    var desiredSource = 'https://sitename.com/js/script.js';
    var scripts = document.getElementsByTagName('script');
    var alreadyLoaded = false;

    for(var scriptIndex in document.scripts) {
        if(!alreadyLoaded && desiredSource === scripts[scriptIndex].src) {
            alreadyLoaded = true;
        }
    }
    if(!alreadyLoaded){
        // Run your code in this block?
    }
})();

这是完美的解决方案。我推荐第二个。
Ilyas karim

如果可以将代码与这些想法结合在一起,那就太好了。
伊利亚斯·卡里姆

document.scripts似乎比快document.getElementsByTagName('script'),但还没有测试它
阿尔文凯斯勒

1
@AlwinKesler,同意。使用其他方法更新了代码。获得基准会很好。
MyStream

3

检查是否加载了外部脚本的另一种方法是,可以使用jquery的数据功能并存储一个验证标志。例如:

if(!$("body").data("google-map"))
    {
        console.log("no js");

        $.getScript("https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&callback=initilize",function(){
            $("body").data("google-map",true);

            },function(){
                alert("error while loading script");
            });
        }
    }
    else
    {
        console.log("js already loaded");
    }

3

将上面的几个答案合并为易于使用的功能

function GetScriptIfNotLoaded(scriptLocationAndName)
{
  var len = $('script[src*="' + scriptLocationAndName +'"]').length;

  //script already loaded!
  if (len > 0)
      return;

  var head = document.getElementsByTagName('head')[0];
  var script = document.createElement('script');
  script.type = 'text/javascript';
  script.src = scriptLocationAndName;
  head.appendChild(script);
}

2

我认为最好使用window.addEventListener('error')捕获脚本加载错误,然后尝试再次加载。当我们从CDN服务器加载脚本时,这很有用。如果无法从CDN加载脚本,则可以从服务器加载脚本。

window.addEventListener('error', function(e) {
  if (e.target.nodeName === 'SCRIPT') {
    var scriptTag = document.createElement('script');
    scriptTag.src = e.target.src.replace('https://static.cdn.com/', '/our-server/static/');
    document.head.appendChild(scriptTag);
  }
}, true);

1

只需检查全局变量是否可用,否则请再次检查。为了防止超过最大调用堆栈,请在检查中设置100ms超时

function check_script_loaded(glob_var) {
    if(typeof(glob_var) !== 'undefined') {
    // do your thing
    } else {
    setTimeout(function() {
    check_script_loaded(glob_var)
    }, 100)
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.