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

Javascript 如何使用YUI进行适当的内存管理以避免泄漏,javascript,dom,memory-leaks,yui,Javascript,Dom,Memory Leaks,Yui,我们正在使用YUI的onclick事件,但我们会快速创建和删除dome节点,这会导致内存泄漏 考虑下面的示例代码,我们多次使用3个嵌套div。顶部和底部div附带了YUI onclick事件。去除这些dom元素而不泄漏内存的正确方法是什么: 我真的没有主意了。如您所见,我尝试实现了我们自己的destroy函数。实际上,destroy工作正常,不会泄漏,但速度很慢 destroy 2函数是YUI destroy函数的“复制”,我们使用它来调试问题所在。看起来YUI的递归清理在\u实例字典中找不到子

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

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

我真的没有主意了。如您所见,我尝试实现了我们自己的
destroy
函数。实际上,
destroy
工作正常,不会泄漏,但速度很慢

destroy 2
函数是YUI destroy函数的“复制”,我们使用它来调试问题所在。看起来YUI的递归清理在
\u实例
字典中找不到子节点

<!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>

你好
YUI()。使用(“节点”、“事件”、函数(Y){
窗口Y=Y;
功能销毁(节点){
(新的Y.Node(Node)).destroy();
var children=node.children;

对于(var i=0;i我不确定您在这里试图实现什么,但在所包含的代码中有几点很突出:

  • var Y=YUI()。use(…)
    --
    use()
    返回YUI实例。无需分配
    window.Y=Y;
  • 使用
    Y.one(el)
    代替
    newy.Node(el)
    Y.Node.one(el)
  • 在每个内部div上使用而不是订阅click事件
  • 使用
    Y.Node.create('internal1inner2')
    。每个div可能不需要节点实例
  • 通过混合原始DOM交互和YUI节点,您可能会在长期内为自己创建更多的工作
  • 这些要点中最重要的是#3和#4。如果使用
    节点,则创建
    (或
    附加
    插入
    前置
    ,等等),传入的标记不会为每个元素创建节点,只有最外层的元素。如果使用事件委派,则不需要单独的节点,这意味着您可以添加div结构并立即调用
    node.destroy()
    (注意不要传递
    true
    ,因为内部标记没有需要清除的节点).
    node.destroy()
    将清除事件监听器,因为您使用的是事件委派,所以您没有该监听器,并在任何用户交互之前从
    \u instances
    字典中删除该节点以释放内存。如果用户单击其中一个节点,该事件将被委派处理程序捕获,并将为
    e.target创建一个节点e> 元素。您可以在事件处理程序中自由调用
    this.destroy()
    ,以重新清除
    目标的节点


    YMMV,考虑到您的代码片段没有反映真实的用例。您也可以在freenode上访问#yui以获得帮助或了解问题。

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

    var destroy = function(dom) {
        var ynode = new Y.Node(dom);
        ynode.purge(true);
        ynode.destroy(true);
    }
    
    我必须说,我对YUI文档非常失望,它说YUI销毁函数是这样的

    第一个参数为true时,它的工作方式与node.purge(true)类似 destroy方法的作用不仅仅是分离事件订阅服务器 API文档以获取详细信息。

    我在YUI中考虑了这个bug,因为当调用递归破坏时它不调用递归清除。而且看起来上面的销毁函数在Firefox 8上很慢(也许其他版本也一样)我确实在DOM树上写下了自己的递归并称为<代码>清除< /代码>。


    和<代码>销毁< /代码>没有<代码>真< /代码> .

    使用事件委派可能是一种选择,但我只是尝试修复一些遗留代码。出于同样的原因,我们已经混合了<代码> yi节点和原始<代码> DOM<代码>。我们将考虑使用委托,尽管它更容易为我们在特定节点上附加事件。感谢您的回答如果您认为行为是一个bug,您应该将其提交到,根据记录,这个用例在YUI 3的最新版本中不可复制,因此显然这已经解决了。