【问题标题】:Load js script only when it has not been loaded already and then only once仅在尚未加载时加载 js 脚本,然后仅加载一次
【发布时间】:2022-02-21 23:53:35
【问题描述】:

我只尝试加载一次大型 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'; 可以工作,但我如何检查脚本是否已加载,然后仅在尚未包含时才调用它?

【问题讨论】:

  • stackoverflow.com/questions/1878358/… 提到了使用其他库动态加载脚本的问题。与 vanilla JS 相同的解决方案会起作用吗?
  • @colonelsanders document.getElementsByTagName('head')[0].appendChild(document.createElement('script')).src = 'conversation.js'; 可以工作,但我看不到它如何检查脚本是否已加载。是什么让它在再次调用时无法再次加载?
  • @user3743069 让我明白你可以通过 $.getScript 加载脚本,并通过成功回调通知它已加载,问题出在哪里?
  • @ProllyGeek 当我尝试这样做时,例如在成功回调中将 var 设置为 true,它表示 var 未定义并再次加载。
  • 使用document.getElementsByTagName('script') 对普通 JS 进行检查并迭代这些工作正常。如果这对您不起作用,那么我可能看不到某些内容,并且重新创建问题的代码笔会有所帮助

标签: javascript jquery


【解决方案1】:

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

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
}

【讨论】:

  • 我知道这是旧的,但亲爱的 Jared pease 为您的答案添加解释。人们通过 Google 找到它,如果他们不仅能找到有效的代码,而且还能找到几句话来说明它的工作原理,那就太好了。
  • @JaredSmith 这里是一个菜鸟问题。我把这段代码 sn-p 或示例用法放在哪里?
  • @legen-waitforit- 你可以把它放在你页面上的内联脚本中 <script> snippetgoeshere </script> 或者你可以将它设置为脚本 src <script src="pathToFileWithSnippet.js"></script>
  • 感谢@JaredSmith。你是legen- 等等.. 等等.. -dary
  • if (!scripts.includes('filePathToJSScript')^ { 后缺少括号,无法编辑。
【解决方案2】:

注意,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】:

如果您确保脚本在源代码中只加载一次,生活会更轻松。如果使用 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 可能仍会异步加载。这意味着可以在加载脚本之前在其他地方对脚本进行调用。您可能还需要编写一个 promise maker 和 promise keeper 来处理这些调用,不是不可能,但是... 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 但是可以拥有承诺守护者。它可以寻找一个全局的 Promise 数组,如果该数组存在,则运行 Promise。

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

【讨论】:

    【解决方案4】:

    一个更简单的解决方案(再次假设 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> 部分的末尾。

    【讨论】:

      【解决方案5】:

      这是一个小函数,它将脚本标签添加到文档并在加载后执行回调。仅当脚本不存在时才会添加。

      export const loadScript = (url, callback) => {
          let script;
          const scripts = Array.from(document.querySelectorAll('script'));
          const existingScript = scripts.find((script) => script.src === url);
          if (existingScript) {
              script = existingScript;
          } else {
              script = document.createElement('script');
              script.type = 'text/javascript';
              script.src = url;
              document.getElementsByTagName('head')[0].appendChild(script);
          }
          
          if (script.readyState) {
              script.onreadystatechange = () => {
                  if (script.readyState === 'loaded' || script.readyState === 'complete') {
                      script.onreadystatechange = null;
                      callback();
                  }
              };
          } else {
              script.onload = () => callback();
          }
      };
      

      【讨论】:

        【解决方案6】:

        在普通的 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>";
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-09-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-05-16
          • 1970-01-01
          相关资源
          最近更新 更多