【问题标题】:How to unload a javascript from an html?如何从 html 中卸载 javascript?
【发布时间】:2011-05-20 21:17:04
【问题描述】:

如何从 DOM 中卸载包含所有已定义对象的 JavaScript 资源?

我正在开发一个简单的框架,可以将 html 片段加载到“主”html 中。每个片段都是自包含的,并且可能包含对其他 JS 和 CSS 文件的引用。 JS 和 CSS 资源被解析并动态添加到 html 中。当从 DOM 中删除/替换片段时,我想删除它的 JS 和 CSS。

如果我删除下面示例中的脚本元素,page1.js 中定义的函数仍然可用。

<html>
  <head>
    <script src="page1.js" type="text/javascript"></script>
  </head>
<body>
...

有没有办法从 DOM 中卸载 page1.js 对象?

========= 我使用的测试代码=======

我尝试了我在下面的 cmets 中得到的建议;使用清理功能删除添加的对象 - 但即使这样也失败了。我用于测试的来源:

<html>
<head>
<script type="text/javascript">
    function loadJSFile(){
        var scriptTag = document.createElement("script");
        scriptTag.setAttribute("type", "text/javascript");
        scriptTag.setAttribute("src", "simple.js");

        var head = document.getElementsByTagName("head")[0];
        head.appendChild(scriptTag);
    }

    function unloadJSFile(){            
        delete window.foo;
        delete window.cleanup;
        alert("cleanedup. typeof window.foo is " + (typeof window.foo));
    }
</script>
</head>
<body>

  Hello JavaScript Delete

  <br/>
  <button onclick="loadJSFile();">Click to load JS</button>
  <br/>
  <button onclick="foo();">call foo()</button>
  <br/>
  <button onclick="unloadJSFile();">Click to unload JS</button>

</body>
</html>

simple.js 源码:

var foo = function(){
    alert("hello from foo");
}

【问题讨论】:

  • 如果您以客观的方式看待它,您正在尝试做与stackoverflow.com/questions/3830133/…中相同的事情。 . iframe 似乎是一种相当正常的方式,可以尽可能多地进行清理。
  • @Ravindra:我不能使用iFrames,因为我不知道片段的维度是多少,另外片段需要与页面上的现有代码进行通信。
  • 资源JS是你自己维护的吗?如果是的话,围绕 JS 的一些架构肯定会有所帮助。下面由 cdhowie 和 elusive 提供的答案会有所帮助
  • 不,资源不是我维护的。它是供其他人使用的框架。这是我的主要问题,我想让 3rd 方开发人员使用它尽可能简单,而无需遵循特定的设计模式。
  • 如果你真的想这样做,在页面顶部放置一个脚本&lt;script src=load_save.js&gt;&lt;/script&gt;,它会结束文档加载,然后使用 AJAX 或其他方式请求同一页面并修改脚本,使其成为 pre-src =网址。使用修改的 pre-src 值加载页面文档修改脚本然后看看有什么变化。

标签: javascript dom


【解决方案1】:

你可以让它们 = null

    function fnc1 (){

    }

    window.fnc1  = null
    //or
    window["fnc1"]  = null

【讨论】:

    【解决方案2】:

    我想出了一个窍门。我想知道几天在这里找到答案,我刚刚意识到一个完美的技巧来做到这一点,而无需尝试卸载 java 脚本。只有你需要做的是在你的main页面的java脚本中创建一个像currentPage这样的全局变量,当你加载页面时,将页面名称分配给currentPage。然后在每个其他 .js 文件中使用 $('document').ajaxComplete() insted of $('document').ready() 添加一个 if 语句作为每个 $('document').ajaxComplete() 函数内的第一行。将其设置为检查 currentPage 变量是否等于新页面名称。在 if 语句中添加所有其他事件。我不太懂英语,所以检查我的代码。这是我在这里的第一个答案,如果我犯了一些错误,请见谅。

    main.html

    <body>
        <div id='container></div>
        <button id="load1">
        <button id="load1">
    </body>
    

    main.js

    var currentPage = "";
    
    $(document).ready(function () {
        $('#load1').click(function () {
            loadSource('page1', 'body');
        });
        $('#load2').click(function () {
            loadSource('page2', 'body');
        });
    });
    
    function loadSource( page, element){
        currentPage = page;
        $('#container').load('views/' + page + '.php', element);
        $.getScript('js/' + page + '.js');
        $('#css').prop('disabled', true).remove();
        $('head').append('<link rel="stylesheet" href="css/' + page + '.css" type="text/css" />');
    }
    

    我所有的页面脚本和样式都在单独的文件夹视图、js、css 中。

    page1.html

    <body>
        <button id="test1">
        <button id="test2">
    </body>
    

    page1.js

    $(document).ajaxComplete(function () {
        if(currentPage == 'page1'){
            /*$('#test1').click(function () {
                console.log('page1');
            });*/
            $('#test2').click(function () {
                console.log('page1');
            });
        }
    });
    

    page2.html

    <body>
        <button id="test1">
        <button id="test2">
    </body>
    

    page2.js

    $(document).ajaxComplete(function () {
        if(currentPage == 'page2'){
            $('#test1').click(function () {
                console.log('page2');
            });
            /*$('#test2').click(function () {
                console.log('page2');
            });*/
        }
    });
    

    我在每个脚本中注释了一个按钮,以检查该按钮是否仍然具有旧脚本的影响。

    【讨论】:

      【解决方案3】:

      我自己正在研究类似的东西,并认为我会发布我的发现

      1. 将你的东西包装在 js 文件的全局命名空间中,这样就可以很容易地删除它,即 var stuff = { blabla: 1, method: function(){} };

      2. 当你需要摆脱它时,只需设置 stuff = {},甚至为 null

      3. 从页面中删除脚本标签

      *** 如果你使用 requirejs - require js remove definition to force reload

      注意:只要您不从其他任何地方引用命名空间内的模块,GC 就会收集所有内容,您就可以开始了。

      【讨论】:

        【解决方案4】:

        不,这是不可能的。您可以构建一个简单的清理函数来删除该文件中定义的所有变量:

        var foo = 'bar';
        var cleanup = function () {
            delete window.foo;
            delete window.cleanup;
        };
        
        // unload all resources
        cleanup();
        

        另一种方法是为您的片段使用模块化对象结构,然后自行清理。这涉及稍高的开销,但可能是值得的,因为它使代码更易于阅读和维护:

        // creates the object using the second parameter as prototype.
        // .create() is used as constructor
        GlobalModuleHandlerThingy.addModule('my_module', {
            create: function () {
                this.foo = 'bar';
                return this;
            },
            foo: null,
            destroy: function () {
                // unload events, etc.
            }
        });
        
        GlobalModuleHandlerThingy.getModule('my_module').foo; // => bar
        GlobalModuleHandlerThingy.unloadModule('my_module'); // calls .destroy() on the module and removes it.
        

        【讨论】:

        • 可能,但需要手动定义清理并可能导致内存泄漏。我需要这个解决方案来编写一个简单的框架,它使单个 html 能够动态加载链接到其他 JS 和 CSS 资源的 html 片段。当片段被替换时,我需要卸载它们的 JS 和 CSS 上下文。
        • @Totach:是的,但这是摆脱这些变量的唯一方法。这样做时需要考虑分离事件等。这只是一个简单的例子。
        • 我尝试了您的解决方案,但出于某种奇怪的原因 - 无法删除对象!? (在 Firefox 中返回 false)。请注意,脚本是通过创建脚本标记动态加载的。任何想法?非常感谢!
        • @Totach:我使用 firebugs 控制台尝试了以下操作:var foo = 'bar', cleanup = function () { delete window.foo; delete window.cleanup; }; cleanup();,它按预期工作。您的确切错误信息是什么?
        • 在控制台中它也适用于我。但是在 html 中,我通过创建脚本标记来加载脚本并将其附加到 head 元素(使用 JavaScript)。当我尝试删除附加脚本添加的对象时,返回“false”并且对象保持定义。我注意到的是,如果我使用命名空间对象,则不能删除命名空间对象,但可以删除命名空间上定义的对象......(再次感谢)
        【解决方案5】:

        如果您需要卸载特定对象,这相当简单:只需将其设置为 {}

        即:myobj = {};

        因此,如果您知道在特定的包含中创建了哪些对象,那一点也不难。

        另一方面,如果您不知道在特定的包含中创建了哪些对象,则没有机制可以找出 - 您不能要求 Javascript 告诉您在特定的包含中定义了什么。

        但是,我想说,如果您不知道特定 javascript 文件中正在加载哪些对象,那么您在加载它时可能不会给自己带来任何好处(您应该始终合理地了解代码在您的网站),或尝试手动卸载它(如果您不知道它的作用,这意味着它包含第三方,这意味着手动取消设置可能会破坏事情)。

        【讨论】:

        • 也可以用函数来完成:function name()={}
        【解决方案6】:

        这是做不到的。

        执行脚本时,函数定义会添加到全局window 对象中。函数可能附加了调试符号,指示函数来自何处,但脚本无法获得此信息。

        实现这样的事情的唯一方法是在脚本中创建一个伪命名空间,然后在完成后丢弃整个命名空间。但是,这个问题向我暗示您正在尝试以错误的方式做某事。也许详细说明您的方案将有助于我们提供替代解决方案。

        【讨论】:

        • 谢谢 - 将对象添加到命名空间然后删除它似乎是最好的方法。
        • @Totach:使用这种方法时,内存泄漏仍然是一个问题,但您可能已经解决了这个问题。
        【解决方案7】:

        也许你需要考虑有条件地加载它而不是有条件地卸载它......

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-10-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-01-14
          • 2019-01-24
          相关资源
          最近更新 更多