防止此javascript代码中的内存泄漏?
我有一个Django管理页面,用于嵌套类别列表,如下所示: 我编写此脚本是为了对列表进行排序并按层次显示:防止此javascript代码中的内存泄漏?,javascript,garbage-collection,django-admin,Javascript,Garbage Collection,Django Admin,我有一个Django管理页面,用于嵌套类别列表,如下所示: 我编写此脚本是为了对列表进行排序并按层次显示: {% extends "admin/change_list.html" %} {% load i18n %} {% block footer %} <script> (function(){ var rows=document.getElementById('result_list').getElementsByTagName('tr'), table=r
{% extends "admin/change_list.html" %}
{% load i18n %}
{% block footer %}
<script>
(function(){
var rows=document.getElementById('result_list').getElementsByTagName('tr'),
table=rows[1].parentNode||rows[1].parentElement,
i=0, r, // skip the first row
data={}; // store category data
while (r=rows[++i]) {
var catName=r.getElementsByTagName('a')[0],
k=catName.innerHTML,
opts=r.getElementsByTagName('select')[0],
j=-1, opt;
while (opt=opts[++j]) {
if (!opt.selected) continue;
data[k] = {
title: k,
children: {},
parentName: opt.innerHTML,
parentId: opt.value,
catName: catName,
row: r
}
}
}
for (var sub in data) {
if (data[sub].parentName == sub) continue;
for (var sup in data) {
if (sup == data[sub].parentName) {
data[sup].children[sub]=data[sub];
data[sub].parent = data[sup];
break;
}
}
}
var alt = 0;
for (var leaf in data) {
if (data[leaf].parentName != leaf) continue;
walk(data[leaf], leaf, function (node, nodeName) {
var n=node, t=n.title;
while (n=n.parent) {
t = ' · ' + t;
}
node.catName.innerHTML = t;
node.row['class']=node.row['className']='row'+alt++%2;
table.removeChild(node.row);
table.appendChild(node.row);
});
}
function walk (leaf, leafName, cb) {
if (cb) cb(leaf, leafName);
leaf.ready = true;
for (var kid in leaf.children) {
if (leaf.children[kid].ready) continue;
walk(leaf.children[kid], kid, cb);
}
}
}());
</script>
{% endblock %}
{%extends“admin/change\u list.html”%}
{%load i18n%}
{%block footer%}
(功能(){
var rows=document.getElementById('result_list').getElementsByTagName('tr'),
table=行[1]。parentNode | |行[1]。parentElement,
i=0,r,//跳过第一行
data={};//存储类别数据
而(r=行[++i]){
var catName=r.getElementsByTagName('a')[0],
k=catName.innerHTML,
opts=r.getElementsByTagName('select')[0],
j=-1,opt;
而(opt=opts[++j]){
如果(!opt.selected)继续;
数据[k]={
标题:k,
儿童:{},
父名称:opt.innerHTML,
parentId:opt.value,
猫名:猫名,
行:r
}
}
}
用于(数据中的var子项){
如果(data[sub].parentName==sub)继续;
用于(var辅助数据){
if(sup==数据[sub].parentName){
数据[sup]。子项[sub]=数据[sub];
数据[sub]。父项=数据[sup];
打破
}
}
}
var-alt=0;
for(数据中的变量叶){
如果(数据[leaf].parentName!=leaf)继续;
漫游(数据[叶]、叶、函数(节点、节点名){
var n=节点,t=标题;
while(n=n.parent){
t='·;'+t;
}
node.catName.innerHTML=t;
node.row['class']=node.row['className']='row'+alt++%2;
table.removeChild(node.row);
table.appendChild(node.row);
});
}
功能漫游(叶、叶名称、cb){
如果(cb)cb(叶,叶名称);
leaf.ready=true;
for(叶中的变量kid.childs){
如果(leaf.children[kid].ready)继续;
步行(叶.儿童[儿童],儿童,cb);
}
}
}());
{%endblock%}
…脚本运行正常,列表如下所示:
我的问题是:我觉得由于父/子对象创建的循环引用,在垃圾收集较弱的UAs中,脚本很容易出现内存泄漏。这是我应该担心的吗?有没有更好的方法来写剧本?我应该删除脚本末尾的一堆东西吗?如果是,是什么 脚本似乎没有包含任何严重的内存泄漏,因为在行走之后,它没有留下任何函数(如cb)。因此,垃圾收集器应该成功地收集所有创建的垃圾
但是,如果迭代次数非常多,那么在执行过程中可能会有较高的内存使用率
[不久前我写了一篇关于这个的文章]
我看到一些小漏洞,即垃圾收集器在清理函数内的活动节点引用时出现问题。这是因为DOM和JavaScript都有自己的垃圾收集器,基本上,它们不想为了引用而互相争吵 既然你每页调用一次这个脚本?内存泄漏很小,实际上可以忽略,除非人们在一次会话中打开100多页。不过,打扫卫生更好
{% extends "admin/change_list.html" %}
{% load i18n %}
{% block footer %}
<script>
(function(){
var rows=document.getElementById('result_list').getElementsByTagName('tr'),
table={},
i=0, r, // skip the first row
data={}; // store category data
// table is now a JS object with a el reference to an element.
table.el = rows[1].parentNode||rows[1].parentElement;
while (r=rows[++i]) { // you skip the first row, that correct? Else use i++
var catName=r.getElementsByTagName('a')[0],
k=catName.innerHTML,
opts=r.getElementsByTagName('select')[0],
j=-1, opt;
while (opt=opts[++j]) {
if (!opt.selected) continue;
data[k] = {
title: k,
children: {},
parentName: opt.innerHTML,
parentId: opt.value,
catName: catName,
row: r
}
}
}
// nullify node references
r = catName = opt = rows = null;
for (var sub in data) {
if (data[sub].parentName == sub) continue;
for (var sup in data) {
if (sup == data[sub].parentName) {
data[sup].children[sub]=data[sub];
data[sub].parent = data[sup];
break;
}
}
}
var alt = 0;
for (var leaf in data) {
if (data[leaf].parentName != leaf) continue;
walk(data[leaf], leaf, function (node, nodeName) {
var n=node, t=n.title;
while (n=n.parent) {
t = ' · ' + t;
}
node.catName.innerHTML = t;
node.row['class']=node.row['className']='row'+alt++%2;
// if table wasn't a JS object, this closure would not have been cleaned up.
// a refence to table is kept, not to a live DOM element.
table.el.removeChild(node.row);
table.el.appendChild(node.row);
});
}
function walk (leaf, leafName, cb) {
if (cb) cb(leaf, leafName);
leaf.ready = true;
for (var kid in leaf.children) {
if (leaf.children[kid].ready) continue;
walk(leaf.children[kid], kid, cb);
}
}
}());
</script>
{% endblock %}
{%extends“admin/change\u list.html”%}
{%load i18n%}
{%block footer%}
(功能(){
var rows=document.getElementById('result_list').getElementsByTagName('tr'),
表={},
i=0,r,//跳过第一行
data={};//存储类别数据
//table现在是一个JS对象,具有对元素的el引用。
table.el=行[1]。parentNode | |行[1]。parentElement;
当(r=rows[++i]){//跳过第一行时,正确吗?否则使用i++
var catName=r.getElementsByTagName('a')[0],
k=catName.innerHTML,
opts=r.getElementsByTagName('select')[0],
j=-1,opt;
而(opt=opts[++j]){
如果(!opt.selected)继续;
数据[k]={
标题:k,
儿童:{},
父名称:opt.innerHTML,
parentId:opt.value,
猫名:猫名,
行:r
}
}
}
//取消节点引用
r=catName=opt=rows=null;
用于(数据中的var子项){
如果(data[sub].parentName==sub)继续;
用于(var辅助数据){
if(sup==数据[sub].parentName){
数据[sup]。子项[sub]=数据[sub];
数据[sub]。父项=数据[sup];
打破
}
}
}
var-alt=0;
for(数据中的变量叶){
如果(数据[leaf].parentName!=leaf)继续;
漫游(数据[叶]、叶、函数(节点、节点名){
var n=节点,t=标题;
while(n=n.parent){
t='·;'+t;
}
node.catName.innerHTML=t;
node.row['class']=node.row['className']='row'+alt++%2;
//若表不是JS对象,那个么这个闭包就不会被清理。
//保留对表的引用,而不是对活动DOM元素的引用。
table.el.removeChild(node.row);
table.el.appendChild(node.row);
});
}
功能漫游(叶、叶名称、cb){
如果(cb)cb(叶,叶名称);
leaf.ready=true;
for(叶中的变量kid.childs){
如果(leaf.children[kid].ready)继续;
步行(叶.儿童[儿童],儿童,cb);
}
}
}());
{%endblock%}
整理起来有点混乱,因为您的JS对象名称暗示它们是DOM elements=p,但我认为我正确地理解了它。但是,您可能想检查一下代码并清空我可能忽略的其他DOM元素(当然,一旦您处理完它们)。您“感觉”脚本容易出现内存泄漏,或者您观察到内存泄漏?我没有观察到任何内存泄漏,但我感觉IE可能会做一些愚蠢的事情,比如在页面导航时不进行垃圾收集。不幸的是,我没有办法测试那个ATM。你们的操作系统允许你们观察RAM的使用情况吗?如果是这样的话,我相信你可以设置一个原始测试,看看是否有多余的内存泄漏……事实上,我想我可以使用google chrome中的
about:memory
来非常有效地做到这一点。我最担心的是