可以卸载动态加载的JavaScript吗?

可以卸载动态加载的JavaScript吗?,javascript,ajax,browser,memory-leaks,Javascript,Ajax,Browser,Memory Leaks,我正在编写一个具有静态外壳和动态内容部分的web应用程序。当用户浏览系统时,动态内容部分有许多更新。加载新内容块时,还可以选择加载另一个JavaScript文件。以良好内务管理的名义,我从DOM中删除了应用于旧内容块的脚本块,因为不再需要JavaScript 接下来的问题是,当我意识到虽然我已经从DOM中删除了元素,但是之前评估的JavaScript仍然可以执行。这当然有道理,但我担心如果用户导航到许多不同的部分,可能会导致内存泄漏 那么问题是,我应该担心这种情况吗?如果是这样的话,有没有办法强

我正在编写一个具有静态外壳和动态内容部分的web应用程序。当用户浏览系统时,动态内容部分有许多更新。加载新内容块时,还可以选择加载另一个JavaScript文件。以良好内务管理的名义,我从DOM中删除了应用于旧内容块的脚本块,因为不再需要JavaScript

接下来的问题是,当我意识到虽然我已经从DOM中删除了
元素,但是之前评估的JavaScript仍然可以执行。这当然有道理,但我担心如果用户导航到许多不同的部分,可能会导致内存泄漏


那么问题是,我应该担心这种情况吗?如果是这样的话,有没有办法强制浏览器清理过时的JavaScript?

您可以采用更面向对象的方法,并以一种方式构建模型,使每个JavaScript块都作为自己的对象,使用自己的方法。卸载该对象后,如果将计算代码保存在名称空间中,只需将该对象设置为
null

,例如:

var MYAPP = {
    myFunc: function(a) { ... }
}
“释放”整个过程应该像将MYPP设置为某个随机值一样简单

MYAPP = 1

这取决于没有其他引用变量的方法,这并不简单

将JS文件加载到iframe中如何?然后(理论上,我从未测试过它),您可以从DOM中删除iframe并删除它正在使用的“内存”


我想。。。或者我希望…

如果您担心内存泄漏,那么您需要确保代码中没有要删除的事件处理程序,并参考仍然存在的dom树

您可能需要保留代码中添加的所有事件处理程序的列表,在卸载之前,检查并删除事件处理程序

我从来没有这样做过,我总是担心删除节点时仍然存在引用

下面是一篇关于javascript内存泄漏的好文章: (这完全是即兴的。)

在当前的浏览器技术中,内存使用确实是一个需要关注的问题,尽管除非我们讨论大量的代码,否则我不知道代码大小是个问题(通常是DOM大小和剩余的事件处理程序)

您可以为可加载模块使用一种模式,这样可以更容易地批量卸载模块,或者至少让浏览器知道它可以卸载模块

考虑:

window.MyModule = (function() {

    alert('This happens the moment the module is loaded.');

    function MyModule() {

        function foo() {
            bar();
        }

        function bar() {
        }

    }

    return MyModule;
})();
它定义了一个闭包,其中包含函数
foo
bar
,它们可以以正常方式相互调用。请注意,函数外部的代码会立即运行

如果您没有将对闭包内部内容的任何引用传递给闭包外部的任何内容,那么window.MyModule将是对该闭包及其执行上下文的唯一引用。要卸载它,请执行以下操作:

try {
    delete window.MyModule;
}
catch (e) {
    // Work around IE bug that doesn't allow `delete` on `window` properties
    window.MyModule = undefined;
}
这会告诉JavaScript环境您不再使用该属性,并使它引用的任何内容都可用于垃圾收集。收集的时间和是否发生显然取决于实现

请注意,如果您在卸载之前在模块内钩住事件处理程序以将其解除钩住,这将非常重要。可以通过返回对析构函数的引用而不是主闭包来实现:

window.MyModule = (function() {

    alert('This happens the moment the module is loaded.');

    function foo() {
        bar();
    }

    function bar() {
    }

    function destructor() {
        // Unhook event handlers here
    }

    return destructor;
})();
脱钩就是:

if (window.MyModule) {
    try {
        window.MyModule();
    }
    catch (e) {
    }
    try {
        delete window.MyModule;
    }
    catch (e) {
        // Work around IE bug that doesn't allow `delete` on `window` properties
        window.MyModule = undefined;
    }
}

JavaScript解释器有垃圾收集器。换言之,如果你不引用任何东西,就不会把它们留在身边

将JSON与回调函数(JSONP)结合使用很好的原因之一

例如,如果每个JS的HTTP响应为:

callback({status: '1', resp: [resp here..]});
如果callback()没有创建对作为参数传入的JSON对象的引用,则函数完成后将对其进行垃圾收集

如果你真的需要做一个引用,那么你可能出于某种原因需要这些数据——否则你本来会/不应该引用它


提到的命名空间对象的方法只是创建一个引用,该引用将被持久化,直到引用计数达到0为止。换句话说,您必须跟踪每个引用并在以后删除它,当您有来自DOM的闭包和引用时,这可能会很困难。只需一个引用就可以将对象保存在内存中,一些简单的操作可能会在您没有意识到的情况下创建引用。

讨论得很好。清理了很多东西。不过,我还有另一个担忧

如果我将window.MyModule.bar()绑定到一个事件,如果删除window.MyModule后意外触发该事件,会发生什么情况?对我来说,命名空间和将js分离为动态加载的模块的全部目的是避免错误地触发跨模块的事件处理程序

例如,如果我这样做(请原谅我的jQuery):

$('.some class')。单击(window.MyModule.bar)


如果我删除window.MyModule,加载另一个模块,然后单击一个元素,该元素意外地拥有一个名为some class的类,会发生什么情况?

为什么不删除MYAPP或MYAPP=undefined?不仅是变量本身,而且可能创建的任何闭包都是其中的函数。@txwinker:是的,我觉得这是隐含的。要使其工作,必须既不引用MYAPP,也不引用其中的任何内容。当涉及到内存泄漏时,会有一些挑剔的细节,比如@Dykam:没有理由不进行未定义,但我避免了删除,因为我对它没有太多经验,而且“1”不应该对OP可能正在做的任何事情造成巨大的内存紧张。