The four types of common JavaScript leaks

The four types of common JavaScript leaks

1: Global variables

function foo(arg) {

bar = "some text";

}

function foo(arg) {

window.bar = "some text";

}

In this example, leaking a simple string won't do much harm, but it could certainly be worse.

Another way in which an accidental global variable can be created is through this:

function foo() {

this.var1 = "potential accidental global";

}

// Foo called on its own, this points to the global object (window)

// rather than being undefined.

foo();

To prevent these mistakes from happening, add 'use strict'; at the beginning of your JavaScript files. This enables a stricter mode of parsing JavaScript that prevents accidental global variables. Learn more about this mode of JavaScript execution.

If you must use a global variable to store lots of data, make sure to assign it as null or reassign it after you are done with it.

2: Timers or callbacks that are forgotten

to explicitly remove these observers before the object is disposed of. For instance:

var element = document.getElementById('launch-button');

var counter = 0;

function onClick(event) {

counter++;

element.innerHtml = 'text ' + counter;

}

element.addEventListener('click', onClick);

// Do stuff

element.removeEventListener('click', onClick);

element.parentNode.removeChild(element);

// Now when element goes out of scope,

// both element and onClick will be collected even in old browsers // that don't handle cycles well.

Nowadays, modern browsers (including Internet Explorer and Microsoft Edge) use modern garbage collection algorithms that can detect these cycles and deal with them correctly

Frameworks and libraries such as jQuery do remove listeners before disposing of a node (when using their specific APIs for that). This is handled internally by the libraries which also make sure that no leaks are produced

3.Closures

var theThing = null;

var replaceThing = function () {

var originalThing = theThing;

var unused = function () {

if (originalThing) // a reference to 'originalThing'

console.log("hi");

};

theThing = {

longStr: new Array(1000000).join('*'),

someMethod: function () {

console.log("message");

}

};

};

setInterval(replaceThing, 1000);

This snippet does one thing: every time replaceThing is called, theThing gets a new object which contains a big array and a new closure (someMethod). At the same time, the variable unused holds a closure that has a reference to originalThing (theThing from the previous call to replaceThing). Already somewhat confusing, huh? The important thing is that once a scope is created for closures that are in the same parent scope, that scope is shared.

In this case, the scope created for the closure someMethod is shared with unused. unused has a reference to originalThing. Even though unused is never used, someMethod can be used through theThing outside of the scope of replaceThing (e.g. somewhere globally). And as someMethod shares the closure scope with unused, the reference unused has to originalThing forces it to stay active (the whole shared scope between the two closures). This prevents its collection.

When this snippet is run repeatedly a steady increase in memory usage can be observed. This does not get smaller when the GC runs. In essence, a linked list of closures is created (with its root in the form of the theThing variable), and each of these closures' scopes carries an indirect reference to the big array, resulting in a sizable leak.

4: Out of DOM references

var elements = {

button: document.getElementById('button'),

image: document.getElementById('image')

};

function doStuff() {

elements.image.src = 'http://example.com/image_name.png';

}

function removeImage() {

// The image is a direct child of the body element.

document.body.removeChild(document.getElementById('image'));

// At this point, we still have a reference to #button in the

//global elements object. In other words, the button element is

//still in memory and cannot be collected by the GC.

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子顺献,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件债查,死亡現(xiàn)場離奇詭異毁嗦,居然都是意外死亡,警方通過查閱死者的電腦和手機娘纷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門嫁审,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人赖晶,你說我怎么就攤上這事律适。” “怎么了遏插?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵捂贿,是天一觀的道長。 經(jīng)常有香客問我胳嘲,道長厂僧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任了牛,我火速辦了婚禮颜屠,結(jié)果婚禮上辰妙,老公的妹妹穿的比我還像新娘。我一直安慰自己甫窟,他們只是感情好密浑,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著粗井,像睡著了一般肴掷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上背传,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天呆瞻,我揣著相機與錄音,去河邊找鬼径玖。 笑死痴脾,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的梳星。 我是一名探鬼主播赞赖,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼冤灾!你這毒婦竟也來了前域?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤韵吨,失蹤者是張志新(化名)和其女友劉穎匿垄,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體归粉,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡椿疗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年倔喂,在試婚紗的時候發(fā)現(xiàn)自己被綠了铝条。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡席噩,死狀恐怖班缰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情班挖,我是刑警寧澤鲁捏,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布芯砸,位于F島的核電站萧芙,受9級特大地震影響给梅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜动羽,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一渔期、第九天 我趴在偏房一處隱蔽的房頂上張望运吓。 院中可真熱鬧,春花似錦疯趟、人聲如沸拘哨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽产镐。三九已至,卻和暖如春踢步,著一層夾襖步出監(jiān)牢的瞬間癣亚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工获印, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留述雾,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓兼丰,卻偏偏與公主長得像绰咽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子地粪,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容