【问题标题】:What is the danger in including the same JavaScript library twice?两次包含同一个 JavaScript 库有什么危险?
【发布时间】:2011-06-20 22:45:26
【问题描述】:

我正在使用的其中一个网络应用程序由许多部分 HTML 文件组成。如果部分需要 JavaScript 库,例如 YUI,则 YUI 库包含在部分中。

当部分在运行时合并时,生成的 HTML 通常会多次包含 YUI 库。

<html>
... 
<script type="text/javascript" src="/js/yahoo/yahoo-min.js"></script>
... 
<script type="text/javascript" src="/js/yahoo/yahoo-min.js"></script>
... 
<script type="text/javascript" src="/js/yahoo/yahoo-min.js"></script>
...
</html>

我多次看到包含 jQuery 的奇怪行为,尤其是在使用 AJAX 时。具体来说,为什么多次包含同一个 JavaScript 库是个坏主意?为什么它只是有时会引起问题?

【问题讨论】:

  • 最大的风险是它会导致浏览器在客户端机器中形成一个奇点,最终成长为一个吞噬整个星球的黑洞……所以请不要这样做。 ;)
  • @FrustratedWithFormsDesigner 如果你把它作为答案,我会投票给你。两次。
  • 如果他把这个作为答案,我会给他 42 次投票。

标签: javascript javascript-framework


【解决方案1】:

每次都会执行。取决于文件,这可能是不可取的。例如,如果文件包含alert("hello"),则每次引用该文件时都会显示警告框,您可能希望它只显示一次。

编写安全库:

如果您只想一次性执行,请按以下方法解决。假设您正在编写一个库foobar.js,它导出一个全局foobar

function foobar() {
 // ...
}

您可以使用如下代码确保文件的任何重复执行都变为无操作:

window.foobar = window.foobar || function foobar() {
  // ...
};

更现代的方法是改用JavaScript modules。 JavaScript 模块最多只能执行一次:

<script type="module" src="example.js"></script>
<script type="module" src="example.js"></script>
<!-- example.js will only be executed once -->

使用不安全的库:

如果您无法修改库的源代码,并且您确定它不安全,这里有一种解决方法,即只加载一次库。创建一个全局并每次使用它来检查脚本是否已经加载。您必须自己将 global 设置为 true。

<script>(function() {
  if (! window.foobar) {
    var script = document.createElement('script');
    script.async = true; // remove this if you don't want the script to be async
    script.src = 'foobar.js';
    document.getElementsByTagName('head')[0].appendChild(script);
    window.foobar = true;
 }
}();</script>

【讨论】:

    【解决方案2】:

    浏览器会缓存文件,只下载一次。然而,它将被执行不止一次。所以性能影响可以忽略不计,但正确性影响可能不会。

    【讨论】:

    • 不过,它会多次评估它。
    • 不过,心跳可以忽略不计。
    • úlio,这个评论没有任何意义。
    • 不一定。它可能必须重建所有对象,并导致大量垃圾收集。这可能需要几十毫秒 - 导致页面加载明显滞后。
    • úlio 评估可能不会很昂贵(就时间而言,或者在这种情况下是心跳),但可能会导致您的代码无法按预期工作。举个例子……加载 jQuery,然后是 jQuery UI,然后是一些自定义的 jQuery UI 小部件。然后再次加载 jQuery UI,哎呀!您的自定义小部件不再存在!
    【解决方案3】:

    根据库,多次包含它可能会产生不良影响。

    可以这样想,如果您有一个将点击事件绑定到按钮的脚本,并且您将该脚本包含两次,那么当点击该按钮时,这些操作将运行两次。

    您可以编写一个简单的函数,调用该函数来加载脚本并让它跟踪已加载的文件。或者,我敢肯定您可能会使用预先存在的 JS 加载器(例如 LabJS)并对其进行修改。

    【讨论】:

    • 一切都是关于重新进入。刚才它是在“模块加载”而不是函数执行方面。设计师是否做了一些(愚蠢的)使第二次包含打破逻辑的事情?通常情况并非如此,但可以想象它是真的场景——尤其是在每次运行都依赖于某些外部状态并且逻辑应用不正确的情况下。
    【解决方案4】:

    你应该采用我学到的方法检查HTML5 Boilerplate的来源:

    <script>
        !window.YAHOO && document.write(
            unescape('%3Cscript src="/js/yahoo/yahoo-min.js"%3E%3C/script%3E')
        );
    </script>
    

    我不使用 YUI,所以将 !window.YAHOO 替换为全局 YUI 使用的任何内容。

    只有在全局范围内尚不存在该库时,此方法才会加载该库。

    【讨论】:

    • 有很多方法可以做到这一点,而无需求助于document.write,它有各种各样的问题。 HTML5 Boilerplate 不再使用这段代码。
    猜你喜欢
    • 2012-02-10
    • 1970-01-01
    • 2012-08-30
    • 2012-01-13
    • 1970-01-01
    • 1970-01-01
    • 2015-03-08
    • 2012-06-30
    相关资源
    最近更新 更多