2009-08-28 69 views
12

我正在编写一个具有静态外部“外壳”和动态内容部分的Web应用程序。动态内容部分在用户导航系统时有许多更新。当一个新的内容块被加载时,它也可以选择加载另一个JavaScript文件。为了良好的家务管理,我从DOM中删除了适用于旧内容块的脚本块,因为不再需要JavaScript。可以动态加载JavaScript卸载吗?

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

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

回答

14

<theory>你可以使用更多的面向对象的方法,并以每块javascript块的方式以其自己的方法来作为自己的对象来构建模型。卸载后,您只需将该对象设置为null</theory>

3

如果您保存在命名空间,如评估代码:

var MYAPP = { 
    myFunc: function(a) { ... } 
} 

“解放出来”整个事情应尽可能设置MYPP一些随机值一样简单,ALA

MYAPP = 1 

这取决于没有其他的方法来引用变量,这是不平凡的

+2

为什么不删除MYAPP或MYAPP = undefined? – Dykam 2009-08-28 13:17:30

+0

不仅变量本身,而且任何可能创建的闭包都是里面的函数。 – txwikinger 2009-08-28 13:19:08

+0

@txwinker:是的,我想我觉得那是暗示的。为了这个工作,不得提及任何MYAPP,也不能提及其中的任何内容。当涉及到泄漏内存和IE时,有一些令人费解的细节。 @Dykam:没有理由不去定义,但是我避免了删除,因为我对它没有太多的经验,而且“1”不应该给OP做任何事情带来巨大的内存压力。 – Svend 2009-08-28 13:34:50

1

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

我想......或者我希望......

1

如果你担心内存泄漏,那么你将要进行一定会出现在代码中没有事件处理要移除指仍然存在dom树。

这可能是因为您需要保留一份您的代码添加的所有事件处理程序的列表,并且在卸载之前通过并移除事件处理程序。

我从来没有这样做过,我总是担心我何时删除了仍然有引用的节点。

这里是一个JavaScript的内存泄漏的好文章: http://javascript.crockford.com/memory/leak.html

9

(这是相当现成的,袖口。)

内存使用确实需要在当前被关注的一个问题虽然除非我们谈论了很多代码,但我不知道代码大小是个问题(通常是DOM大小和剩余的事件处理程序)。

您可以使用可加载模块的模式,使其更容易卸载它们 - 或者至少让浏览器知道它可以卸载它们。

考虑:

window.MyModule = (function() { 

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

    function MyModule() { 

     function foo() { 
      bar(); 
     } 

     function bar() { 
     } 

    } 

    return MyModule; 
})(); 

即定义了包含功能foobar,其可以相互调用以正常方式的封闭件。请注意,函数外的代码会立即运行。

如果你不关闭封闭内部对封闭内部的任何引用,那么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; 
    } 
} 
0

JavaScript解释器有垃圾收集器。换句话说,如果你没有引用任何东西,它不会让它们在周围。

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

例如,如果HTTP响应每个JS是:

callback({status: '1', resp: [resp here..]}); 

如果回调()不创建到传递作为参数的JSON对象的引用,这将是垃圾的功能后,收集完成。

如果你真的需要做一个参考,那么你可能需要这些数据 - 因为某种原因 - 否则你将/不应该首先引用它。

对名称空间对象提及的方法只是创建一个引用,该引用将持续到引用计数为0。换句话说,您必须跟踪每个引用并稍后删除它,当您关闭时可能会很难并且来自DOM的引用位于周围。只有一个引用会将该对象保留在内存中,并且一些简单的操作可能会在您没有意识到的情况下创建引用。

0

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

如果我将window.MyModule.bar()绑定到一个事件,如果在window.MyModule被删除后意外触发事件会发生什么?对我来说,命名空间和将js分隔成动态加载模块的重点是避免错误地触发事件处理程序跨模块。

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

$(”一些一流的。)点击(window.MyModule.bar)。

如果我删除window.MyModule,加载另一个模块,然后点击一个意外有一个叫做some-class的类的元素,会发生什么?