2009-08-28 113 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的類的元素,會發生什麼?