Как правильно управлять памятью с помощью YUI, чтобы избежать утечек - PullRequest
3 голосов
/ 16 декабря 2011

Мы используем события YUI onclick, но мы быстро создаем и удаляем купольные узлы, и это приводит к утечке памяти.

Рассмотрим приведенный ниже пример кода. У нас много 3-х вложенных элементов div много раз.К верхнему и нижнему элементам div прикреплены события YUI onclick.Что является правильным способом избавиться от этих элементов dom, а не утечки памяти:

У меня действительно нет никаких идей.Как видите, я пытался реализовать нашу собственную функцию destroy.На самом деле destroy работает и не течет, но медленно.

Функция destroy2 является «копией» функции уничтожения 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 ]

6 голосов
/ 17 декабря 2011

Я не уверен, что вы пытаетесь достичь здесь, но некоторые вещи выделяются во включенном коде:

  1. var Y = YUI().use(…) - use() возвращает экземпляр YUI. Нет необходимости назначать window.Y = Y;
  2. Используйте Y.one(el) вместо new Y.Node(el) или Y.Node.one(el)
  3. Используйте делегирование события вместо подписки на событие click на каждом внутреннем div
  4. Используйте Y.Node.create('<div><div>inner 1<div>inner2</div></div></div>'). Вам, вероятно, не нужны экземпляры Node для каждого div
  5. Вы, вероятно, создадите больше работы для себя в долгосрочной перспективе, смешивая необработанное взаимодействие DOM и YUI Nodes. Если вы используете YUI, используйте API YUI.

Наиболее важными из этих пунктов являются № 3 и № 4. Если вы используете Node.create (или append, insert, prepend и т. Д.), Переданная разметка не будет иметь узлов, созданных для каждого элемента, только самый внешний элемент. Если вы используете делегирование событий, вам не понадобятся отдельные узлы, что означает, что вы можете добавить свои структуры div и немедленно вызвать node.destroy() (уведомление не проходит true, потому что внутренняя разметка не имеет узлов, нуждающихся в очистке). node.destroy() удалит прослушиватели событий, которых у вас нет, поскольку вы используете делегирование событий, и удалите узел из словаря _instances, чтобы освободить память перед любым взаимодействием с пользователем. Если пользователь нажимает на один из узлов, событие будет перехвачено обработчиком делегата, и для элемента e.target будет создан узел. Вы можете позвонить this.destroy() в обработчике событий, чтобы заново очистить узел target.

YMMV, учитывая, что ваш фрагмент кода не отражает реальный вариант использования. Вы также можете зайти в #yui на freenode, чтобы получить помощь или разобраться с проблемой.

0 голосов
/ 30 декабря 2011

Вот что я сделал, чтобы избежать утечек памяти:

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, потому что она не вызывает рекурсивную очистку, когда вы вызываете уничтожить рекурсивно. Кроме того, похоже, что описанная выше функция уничтожения работает очень медленно в Firefox 8 (возможно, и в других версиях). Я написал свою собственную рекурсию в дереве dom и вызвал purge и destroy без true.

...