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

时间:2011-12-16 03:32:37

标签: javascript dom memory-leaks yui

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

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

我真的没有任何想法。如您所见,我尝试实现自己的destroy函数。实际上destroy有效且不泄漏,但速度很慢。

destroy2功能是' copy'我们用来调试问题的YUI销毁功能。看起来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>

2 个答案:

答案 0 :(得分:6)

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

  1. var Y = YUI().use(…) - use()返回YUI实例。无需指定window.Y = Y;
  2. 使用Y.one(el)代替new Y.Node(el)Y.Node.one(el)
  3. 使用event delegation而不是订阅每个内部div上的click事件
  4. 使用Y.Node.create('<div><div>inner 1<div>inner2</div></div></div>')。您可能不需要每个div的Node实例
  5. 通过混合原始DOM交互和YUI节点,您可能会在长期内为自己创造更多的工作。如果您正在使用YUI,请使用YUI的API。
  6. 这些要点中最重要的是#3和#4。如果您使用Node.create(或appendinsertprepend等),则传入的标记将不会为每个元素创建节点,只会创建最外层元素。如果您使用事件委派,则不需要单独的节点,这意味着您可以添加div结构并立即调用node.destroy()(注意不要传递true,因为内部标记没有需要清除的节点)。 node.destroy()将清除事件侦听器,这是因为您正在使用事件委派而没有,并且在_instances字典中删除节点以在任何用户交互之前释放内存。如果用户单击其中一个节点,则委托处理程序将捕获该事件,并为e.target元素创建节点。您可以在事件处理程序中调用this.destroy()来重新清除target的节点。

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

答案 1 :(得分:0)

以下是我为避免内存泄漏而采取的措施:

var destroy = function(dom) {
    var ynode = new Y.Node(dom);
    ynode.purge(true);
    ynode.destroy(true);
}

我不得不说我对YUI文档说这个YUI销毁函数非常失望。

  

使用true作为第一个参数,它的作用类似于node.purge(true)。该   destroy方法不仅仅是分离事件订阅者。阅读   API文档了解详细信息。   http://yuilibrary.com/yui/docs/event/

我在YUI中考虑这个错误,因为当你以递归方式调用destroy时,它不会调用递归清除。另外看起来上面的破坏功能在Firefox 8上很慢(也许是其他版本)我在dom树上编写了我自己的递归并调用了purgedestroy没有true