精品伊人久久大香线蕉,开心久久婷婷综合中文字幕,杏田冲梨,人妻无码aⅴ不卡中文字幕

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Leak Free Javascript Closures

Leak Free Javascript Closures

October 20, 2005

Javascript closures can be a powerful programming technique. Unfortunately in Internet Explorer they are a common source of memory leaks. Therefore I propose a method to create closures that don‘t leak memory.

Problem

First start with a short explanation of the problem I tried to fix. Here is an example of a simple event handler (IE only for clarity):

function attach(){var element = document.getElementById("my-element");element.attachEvent("onclick", function(){ alert("Clicked: " + element.innerHTML); });}

This seems harmless enough, but the function (closure) is created in a scope which contains element. Since we attach the function to element, a circular reference is created and IE no longer can garbage collect element. This can easily be demonstrated by adding a large string to element.

There are a lot of solutions for this problem, of which most focus on event attaching. But this problem can also occur when Javascript objects are set as a property on an HTML element.

Solution

So we need a function that can access an HTML element without creating an inline closure that leaks memory.

The following code adds a closure method to each function. closure wraps the original function in such a way that this is set to the given object.

Function.prototype.closure = function(obj){// Init object storage.if (!window.__objs)window.__objs = [];// Init closure storage.if (!this.__closureFuncs)this.__closureFuncs = [];// Make sure the object has an id and is stored in the object store.var objId = obj.__closureObjId;if (!objId)__objs[objId = obj.__closureObjId = __objs.length] = obj;// See if we previously created a closure for this object/function pair.var closureFunc = this.__closureFuncs[objId];if (closureFunc)return closureFunc;// Clear reference to keep the object out of the closure scope.obj = null;// Create the closure, store in cache and return result.var me = this;return this.__closureFuncs[objId] = function(){return me.apply(__objs[objId], arguments);};};

So now we can do:

function attach(){var element = document.getElementById("my-element");element.attachEvent("onclick", clickHandler.closure(element));}function clickHandler(){alert("Clicked: " + this.innerHTML);}

Which doesn‘t leak. And can also be used to run any function in a given context:

function myObject(){this.status = "waiting";setTimeout(this.delayedCode.closure(this), 1000);}myObject.prototype ={delayedCode: function(){this.status = "done waiting";}};var o = new myObject();

Some might argue that this fixes one leak with another since all closure context objects are stored in an array. Though this array will be freed on reload, it will stay in memory as long as the user stays on the page.

A simulation of a highly dynamic webpage shows that this isn‘t a big problem in practise. This shows that an html element takes about 1KB and even an application like Xopus doesn‘t create more than 10000 elements in a single session. And even if it would, it would only take about 10MB which I think is acceptable.

Update: new version with less prerequisites

The above mentioned closure function will only work if the original function does not have a (indirect) reference to the object to which the closure is attached. So this will still leak:

function attach(){function clickHandler(){alert("Clicked: " + this.innerHTML);}var element = document.getElementById("my-element");element.attachEvent("onclick", clickHandler.closure(element));}

This is caused by the fact that the created closure function still has a reference to it‘s original function (me). A new version of the closure function fixes that problem:

Function.prototype.closure = function(obj){// Init object storage.if (!window.__objs){window.__objs = [];window.__funs = [];}// For symmetry and clarity.var fun = this;// Make sure the object has an id and is stored in the object store.var objId = obj.__objId;if (!objId)__objs[objId = obj.__objId = __objs.length] = obj;// Make sure the function has an id and is stored in the function store.var funId = fun.__funId;if (!funId)__funs[funId = fun.__funId = __funs.length] = fun;// Init closure storage.if (!obj.__closures)obj.__closures = [];// See if we previously created a closure for this object/function pair.var closure = obj.__closures[funId];if (closure)return closure;// Clear references to keep them out of the closure scope.obj = null;fun = null;// Create the closure, store in cache and return result.return __objs[objId].__closures[funId] = function (){return __funs[funId].apply(__objs[objId], arguments);};};

We can now use the common pattern of creating event handlers inline:

function attach(){var element = document.getElementById("my-element");element.attachEvent("onclick", function(){alert("Clicked: " + this.innerHTML);}.closure(element));}

So now we have truly leak free closures.

In addition we can also easily remove an object from the global array. The following code allows the garbage collector to free an object if there are no other references to it:

window.__objs[obj.__objId] = null;
本站僅提供存儲服務,所有內容均由用戶發布,如發現有害或侵權內容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
+ JavaScript の質問用スレッド vol.76 + | Rちゃんねる
判斷事件是不是發生在某組件中的 JS 函數 - BeanSoft‘s Java Blog ...
js倒計時刷新
vc++訪問javascript(2)
Javascript開發經驗談(轉)
js筆記合集
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯系客服!

聯系客服

主站蜘蛛池模板: 沾化县| 樟树市| 称多县| 静安区| 乌拉特前旗| 西乡县| 金湖县| 绥宁县| 衢州市| 伊金霍洛旗| 定远县| 洛宁县| 绥芬河市| 乳山市| 阿荣旗| 玛纳斯县| 韩城市| 海门市| 福贡县| 丹凤县| 湘乡市| 葫芦岛市| 嘉祥县| 湾仔区| 嘉禾县| 云安县| 文安县| 石狮市| 肥城市| 哈巴河县| 兰溪市| 建湖县| 拉孜县| 高雄市| 宜城市| 武平县| 行唐县| 岚皋县| 蒙自县| 肥城市| 湟源县|