如何使用YUI进行适当的内存管理以避免泄漏

Nik*_*sov 3 javascript yui dom memory-leaks

我们正在使用YUI的onclick事件,但我们会快速创建和删除圆顶节点,这会导致内存泄漏.

考虑下面的示例代码,我们有很多次3个嵌套的div.顶部和底部div附加了YUI onclick事件.什么是摆脱那些dom元素而不是泄漏内存的正确方法:

我真的没有任何想法.如您所见,我尝试实现自己的destroy功能.实际上destroy工作并且不泄漏,但它很慢.

destroy2函数是YUI destroy函数的'copy',我们用它来调试问题所在.看起来YUI的递归清理无法在_instances字典中找到子节点

<!DOCTYPE html5>
<html>
    <head>
        <script src="http://yui.yahooapis.com/3.4.1/build/yui/yui-min.js"></script>
    </head>
    <body>
        <div id="main">hi there</div>
        <script>

        YUI().use("node", "event", function(Y) {

            window.Y = Y;

            function destroy(node) {
                (new Y.Node(node)).destroy();
                var children = node.children;
                for (var i = 0; i<children.length; i++) {
                    destroy(children[i]);
                }
            }

            function destroy2(node, recursive) {

                var UID = Y.config.doc.uniqueID ? 'uniqueID' : '_yuid';

                // alert(1);
                if (recursive) {

                    var all = node.all("*");
                    // alert(all);

                    Y.NodeList.each(all, function(n) {
                        instance = Y.Node._instances[n[UID]];
                        // alert(instance);
                        if (instance) {
                           destroy2(instance);
                        }
                    });

                }

                node._node = null;
                node._stateProxy = null;
                delete Y.Node._instances[node._yuid];
                // node.destroy();
            }

            var main = new Y.Node("#main");

            var divs = [];
            var iter = 0;

            Y.later(10, window, function() {

            iter ++ ;
            var i;
            for (i=0; i<divs.length; i++) {
                var d = divs[i];
                d.parentNode.removeChild(d);


                // (new Y.Node(d)).destroy(true);
                //destroy(d);
                //destroy2(new Y.Node(d), true);
                (new Y.Node(d)).destroy(true);

            }
            divs = [];

            for (i=0; i<1000; i++) {

                var d = document.createElement("div");

                var i1;
                var i2;
                d.appendChild(i1=document.createElement("div"));
                i1.appendChild(document.createTextNode('inner 1'));
                i1.appendChild(i2=document.createElement("div"));
                i2.appendChild(document.createTextNode('inner 2'));
                Y.on("click", function() {
                    alert("inner click")
                }, i2);

                // try to tell YUI to make Node elements
                Y.Node.one(d);
                Y.Node.one(i1);
                Y.Node.one(i2);

                    // new Y.Node(d);
                // new Y.Node(i1);
                // new Y.Node(i2);

                d.appendChild(document.createTextNode("this is div " + iter + " " + i));

                Y.on("click", function(){ alert("you clicked me");}, d);
                main.appendChild(d);

                //divs.push(i2);
                divs.push(d);

            }

          }, null, true);

        })
        </script>

    </body>

</html>
Run Code Online (Sandbox Code Playgroud)

Luk*_*uke 6

我不确定你在这里想要完成什么,但是在包含的代码中有一些突出的东西:

  1. var Y = YUI().use(…)- use()返回YUI实例.无需分配window.Y = Y;
  2. 使用Y.one(el)而不是new Y.Node(el)Y.Node.one(el)
  3. 使用事件委派而不是订阅每个内部div上的click事件
  4. 使用Y.Node.create('<div><div>inner 1<div>inner2</div></div></div>').您可能不需要每个div的Node实例
  5. 通过混合原始DOM交互和YUI节点,您可能会为自己创建更多的工作.如果您使用的是YUI,请使用YUI的API.

其中最重要的是#3和#4.如果你使用Node.create(或append,insert,prepend等),通过在标记不会对每一个元素,只有最外层的元素创建节点.如果使用事件委派,则不需要单独的节点,这意味着您可以添加div结构并立即调用node.destroy()(注意不通过,true因为内部标记没有需要清除的节点). node.destroy()将清除事件监听器,因为您正在使用事件委派,所以您没有这些监听器,并且_instances在任何用户交互之前从字典中删除节点以释放内存.如果用户单击其中一个节点,则委托处理程序将捕获该事件,并为该e.target元素创建节点.您可以this.destroy()在事件处理程序内部调用以重新清除target节点.

YMMV,考虑到你的代码片段并不反映真实的用例.您也可以在freenode上停留#yui以获得帮助或解决问题.