仅在尚未加载js脚本时加载js脚本,然后仅加载一次

时间:2014-10-13 01:00:50

标签: javascript jquery

我一直在尝试加载一个大的js脚本。我没有在页面加载时加载它,因为它不需要,并且会减慢页面加载速度。

所以我一直在尝试使用jQuery的$ .getScript和Modernizr.load加载它(因为我已经使用了Modernizr)。

我已经尝试遍历所有<script></script>元素并检查它们的src属性,看看这个脚本是否是其中之一,但每次运行测试时仍然会加载它们。

我还尝试在脚本开头设置一个全局变量为true,并检查是否已设置并且每次检查时它仍然加载。 以下是我在那个例子中所做的事情:

Modernizr.load({
    test:if(window.flag === undefined),
    yep:'conversation.js',
    callback:function(){    
        antecedent();   
    }
});

var flag = true;设置在conversation.js的第一行

当调用此测试以检查它是否已加载并且仅加载一次之后,有没有人有任何想法如何让这个脚本加载一次呢?

**编辑/更新:** document.getElementsByTagName('head')[0].appendChild(document.createElement('sc‌​ript')).src = 'conversation.js';可以正常工作,但如何检查脚本是否已加载,然后仅在尚未包含脚本时调用此脚本?

5 个答案:

答案 0 :(得分:14)

首先,您需要检查脚本是否已在页面上:

var list = document.getElementsByTagName('script');
var i = list.length, flag = false;
while (i--) {
    if (list[i].src === 'filePathToJSScript') {
        flag = true;
        break;
    }
}

// if we didn't already find it on the page, add it
if (!flag) {
    var tag = document.createElement('script');
    tag.src = 'filePathToJSScript';
    document.getElementsByTagName('body')[0].appendChild(tag);
}

条件中的代码可用于动态地向页面添加脚本。

ES 6更新

ES 6简化了这一点:

let scripts = Array
    .from(document.querySelectorAll('script'))
    .map(scr => scr.src);

if (!scripts.includes('filePathToJSScript')) {
  // same as above
}

答案 1 :(得分:1)

如果您确保脚本仅在源代码中加载一次,则生活会更容易。如果使用php加载脚本,让它也处理依赖项。

函数是第一类对象,如果对象不存在,则在if语句中转换为布尔值false。

if (myFunction) { /* myFunction exists in myscript */
} else {
    var myScript = document.createElement('script');
    document.getElementById("main").appendChild(myScript);
    myScript.src = "http://example/myscript.js";
}

但是,这会导致脚本异步加载。使用document.write仍可能异步加载。这意味着在加载脚本之前可以在其他地方对脚本进行调用。您可能还需要编写一个承诺制造商并承诺管理员处理这些调用,但不是不可能,但...... onload用于做出承诺,如果它没有加载我的承诺就被打破了。

if (myFunction) {
    /* Call the function I needed no promise needed. */
    myFunction();
} else { /* myFunction exists in myscript */
    var myScript = document.createElement('script');
    document.getElementById("main").appendChild(myjsonp);
    myScript.onload = "/* promise fulfillment */"
    myScript.src = "http://example/myscript.js";
} 

所有这些编码可能最终会消除在每个页面上都没有加载它的任何好处,无论是否使用它,让它成为整个站点的缓存资产。

注意脚本的onload只是HTML5。

然而,

myscript.js可以拥有承诺守护者。它可以查找一个全局,它是一个promises数组,如果该数组存在则运行promises。

如果myscript.js加载了jquery ajax,则promise函数可以包含done函数。

答案 2 :(得分:1)

注意,console.log(Modernizr.hasOwnProperty("load"))的返回值是多少? 。见http://github.com/SlexAxton/yepnope.js#deprecation-notice

  

“由于这些原因,我们也不会将yepnope包括在内   Modernizr的下一个版本为Modernizr.load。“


尝试

$(function() {
    var callbacks = $.Callbacks("once");
    callbacks.add(
        $.getScript("conversation.js", function(data, textStatus) {
          console.log(textStatus, window.flag)
        })
    );
    if (window.flag === undefined) {
      callbacks.fire()    
    } else {
      console.log(window.flag)
    }
})

jsfiddle http://jsfiddle.net/guest271314/voehd4ne/

答案 3 :(得分:0)

更简单的解决方案(再次假设ES6)将是:

function load_script(url) {
  if (!Array.from(document.querySelectorAll('script')).some(elm => elm.src == url)) {
    let script = document.createElement('script')
    script.src = url
    document.getElementsByTagName('head')[0].appendChild(script)
  }
}

如果任何元素包含一个作为URL的src,.some()函数将返回true,然后允许您将该元素添加到脚本的<head>部分的末尾。

答案 4 :(得分:0)

在普通的 php 中:

$JSsrcs = isset($JSsrcs) ? $JSsrcs : [];
function js_src_once($JSsrc)
{
    global $JSsrcs;
    if(in_array($JSsrc, $JSsrcs))
    {
        //return "duplicate";
    }
    else
    {
        $JSsrcs[]= $JSsrc;
        return "<script src=\"".$JSsrc."\"></script>";
    }
}