Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Еще раз про очистку массива в js(интересный случай) (https://javascript.ru/forum/misc/53648-eshhe-raz-pro-ochistku-massiva-v-js-interesnyjj-sluchajj.html)

OlegUP 12.02.2015 09:44

Еще раз про очистку массива в js(интересный случай)
 
Добрый день, уважаемые новички и ниндзи!
Почти каждый виджет в моем проекте, навешен его реализующий класс, во время рендеринга виджетов менеджер объектов содержащий массив экземпляров классов виджетов, этот массив чистит, и заполняет заново у меня это прописано вот так:
this.widgets = []; // далее в цикле по селекторам создает через new для блоков виджетов функции их обрабатывающие

В одном виджете я заметил, что при нажатии на кнопку, после которой происходит переинициализация массива widgets действие при следующем клике(n - ном клике) выполяется 2^(n-1) раз, пофиксил отвязкой handler'а перед вызовом функции реинициализации менеджера, но выходит, что объекты-функции из массива не удаляются, а это ест память, как это объяснить и исправить? :help:

OlegUP 12.02.2015 09:47

Сейчас протестил, и
this.widgets.length = 0

не помогает

Erolast 12.02.2015 09:54

Цитата:

далее в цикле по селекторам создает через new для блоков виджетов функции их обрабатывающие
Покажи подробней

И зачем тебе вообще этот массив?

OlegUP 12.02.2015 10:00

Массив экземпляров объектов функции виджетов, которые содержат обработчики событий на элементах каждого виджета в себе(на странице может быть несеолько виджжетов одного типа)

Erolast 12.02.2015 10:01

Цитата:

Массив экземпляров объектов функции виджетов
Выражайся нормально. Что за объекты функций? Что за экземпляры объектов?
Цитата:

, которые содержат обработчики событий на элементах каждого виджета в себе(на странице может быть несеолько виджжетов одного типа)
Зачем?

OlegUP 12.02.2015 10:02

даже проход с удалением и реинициализацией нулем не помог

OlegUP 12.02.2015 10:05

Цитата:

Почти на каждый виджет в моем проекте, навешен его реализующий класс, во время рендеринга виджетов менеджер объектов содержащий массив экземпляров классов виджетов, этот массив чистит, и заполняет заново
все итак уже объяснил вроде

OlegUP 12.02.2015 10:05

Цитата:

Почти каждый виджет в моем проекте, навешен его реализующий класс, во время рендеринга виджетов менеджер объектов содержащий массив экземпляров классов виджетов, этот массив чистит, и заполняет заново
все итак уже объяснил вроде

OlegUP 12.02.2015 10:10

Какая разница зачем и как сделано, сделано все исходя из требований к проге, проще говория есть массив объектов которые содержат методы для работы с виджетом, вопрос в другом, почему после чистки массива некоторые обработчики срабатывают 2, 4, 8, 16... раз

Erolast 12.02.2015 10:10

Цитата:

все итак уже объяснил вроде
Нет, ты объяснил, какие с этим массивом производятся манипуляции, но ты не объяснил, зачем он вообще нужен.

Цитата:

есть массив объектов которые содержат методы для работы с виджетом
Еще раз - зачем?
Цитата:

Какая разница зачем и как сделано
Такая, что все через жопу сделано.

Цитата:

вопрос в другом, почему после чистки массива некоторые обработчики срабатывают 2
Потому что, очевидно, с самих элементов ты ссылки на обработчики не снимаешь.

Цитата:

Цитата:

далее в цикле по селекторам создает через new для блоков виджетов функции их обрабатывающие
Покажи подробней

OlegUP 12.02.2015 10:20

1. допустим есть виджет текстового поля(с множеством значений), естественно у каждого поля свой id в базе и оно уникально, они принадлежат объекту, каждое поле отображается на клиент в виде виджета(в каждом производятся операции например удаление, добавление значения, переименование поля, перерисовка).
2. тогда есть класс виджета тектового поля от которого элементу виджета сопоставляет функции для управления записью в нем,
3. Теперь допустим в объекте 3 поля, на каждое естественно, надо навесить отдельный экземпляр объектов класса WidgetTextField, для этого используется глобальный менеджер, который инициализирует такие объекты для ВСЕХ виджетов на странице.

OlegUP 12.02.2015 10:25

допусти в виджете объекта мы раз нажади кнопку добавить поле;
1. поле добавилось
2. происходит рендеринг виджета, в котором менеджер перезапускается
кликнули 2 раз, (1,2) выполнилось 2 раза, 3 раз - 4 раза, а менеджер говорит на консоль каждый раз когда запускается

OlegUP 12.02.2015 10:27

Но так происходит только в этом виджете, виджет текстового поля при нажатии на кнопку добавляния значения всегда 1 раз срабатывает, и напомню, каждый клик на виджете перезапускает менеджер.

Erolast 12.02.2015 10:33

Цитата:

Цитата:

далее в цикле по селекторам создает через new для блоков виджетов функции их обрабатывающие
Покажи подробней
Кодом, если можно.

Цитата:

1. допустим есть виджет текстового поля(с множеством значений), естественно у каждого поля свой id в базе и оно уникально, они принадлежат объекту, каждое поле отображается на клиент в виде виджета(в каждом производятся операции например удаление, добавление значения, переименование поля, перерисовка).
2. тогда есть класс виджета тектового поля от которого элементу виджета сопоставляет функции для управления записью в нем,
3. Теперь допустим в объекте 3 поля, на каждое естественно, надо навесить отдельный экземпляр объектов класса WidgetTextField, для этого используется глобальный менеджер, который инициализирует такие объекты для ВСЕХ виджетов на странице.
Ты там свой MVC-фреймворк, чтоли, велосипедишь? Почему бы не использовать уже готовые Backbone+Marionette/Chaplin, React или Angular?

OlegUP 12.02.2015 10:34

Никакой не через жопу, все в соответствии с ооп на javascript, если ты не знаком с этим то не надо тут кричать что все через жопу, а вопрос простой и повторю его еще раз: почему после очистки массива хендлеры остаются

OlegUP 12.02.2015 10:35

Manager = function() {
    // Срабатывает каждый раз при изменении блока #main_frame
    // Это нужно для того чтобы переинициализировать виджеты
    this.widgets = [];

    this.run = function () {
        console.log("manager runned ...");
        w_blocks = $('.widget');
        for(i in this.widgets) {
            delete this.widgets[i];
            this.widgets[i] = 0;
        }
        this.widgets = [];
        for (var i = 0; i < w_blocks.length; i++) {
            $(w_blocks[i]).attr('w_id', i);
            var options = ($(w_blocks[i]).attr('options'));
            options = (options == undefined || options =="") ? ",{}" : "," + options;
            var call_str = "new " + $(w_blocks[i]).attr('widget') + "('[w_id=" + i + "]'" + options + ")";
            console.log(call_str);
            this.widgets[i] = eval(call_str);
        }
    };
};

OlegUP 12.02.2015 10:39

Примерный вывод
manager runned ...
new ObjectsList('[w_id=0]',{'filters': {'need_fields': False}})

Erolast 12.02.2015 11:04

Цитата:

Никакой не через жопу, все в соответствии с ооп на javascript, если ты не знаком с этим то не надо тут кричать что все через жопу
Я не понял, ты хочешь помощи или повыпендриваться? Я-то как раз прекрасно знаю, как делается ООП в JS, иначе б я тут не сидел.

Цитата:

for(i in this.widgets) {
Не итерируй так массивы.

Цитата:

Manager = function() {
w_blocks = $('.widget');
Объявление без var/let в современной спецификации JS запрещено. Переключись в строгий режим - код сразу перестанет работать.

Цитата:

eval(call_str);
Лучше не используй eval, когда без него можно обойтись. Выполняемый через него код не может быть пропущен через оптимизатор, что рано или поздно приведет к серьезным лагам.

Цитата:

а вопрос простой и повторю его еще раз: почему после очистки массива хендлеры остаются
Цитата:

Потому что, очевидно, с самих элементов ты ссылки на обработчики не снимаешь.

caetus 12.02.2015 11:32

может я что то не понимаю но спрошу !
зачем делать вот так ??

delete this.widgets[i]; /// undefined
this.widgets[i] = 0; /// теперь undefined меняешь на 0
this.widgets = []; // и тут полностью очищаешь массив !

покажи как ты вешаешь события и удаляешь !!

Erolast 12.02.2015 11:36

Все правильно понимаешь, ерунду он делает.
Тем более что через delete элементы массива удалять нельзя.

OlegUP 12.02.2015 13:17

да обход с удалением и инииализацией нулем я для теста сделал, в учебных пособиях говорится что достаточно сделать
arr = [] или arr.lenth = 0

Вот код одного из виджетов:
function ObjectWidget(block, options) {
        Widget.apply(this, [block, options]);
        var self = this;

        self.options.widget = self.block.attr('widget');
        self.obj_name = self.block.find('.obj_name').find('span').text();
        self.options.obj_id = self.block.attr('obj_id');

        self.block.find(".obj_name").click(function(){self.changeName(this)});
        self.block.find(".delete").click(function(){self.del()});
        self.block.find(".close").click(function(){self.close()});
        self.block.find(".add_field").click(function(){self.add()});

        var mfHeight = parseInt($('#container').css('height'));
        var hHeight  = parseInt(self.block.find('.obj_w_header').css('height'));
        self.block.find('.scroll-pane').css('height', mfHeight-hHeight-15+'px');
        self.block.find('.scroll-pane').jScrollPane();
    }
    ObjectWidget.prototype.del = function () {
        this.options.action = "delete";
        var result_container = $("#main_frame");
        this.render(result_container);
    };

OlegUP 12.02.2015 13:21

По сути, если удалить объект из массива, должен удалиться и обработчик, или объект не удаляется из за того что ссылка повешена на элементе? Но ведь я заменяю сам элемент либо через replaceWith(ajax_result) либо через html(ajax_result) потом запускаю менеджер

caetus 12.02.2015 13:33

ты вешаешь на елемент DOM вот удаляй его или обработчик с него !

я Jquery к счастью плохо знаю но мне кажется что много у тебя обработчиков !
почитай о всплытие !

self.block.find(".obj_name").click(function(){self .changeName(this)});
self.block.find(".delete").click(function(){self.d el()});
self.block.find(".close").click(function(){self.cl ose()});
self.block.find(".add_field").click(function(){sel f.add()});

Erolast 12.02.2015 13:35

Цитата:

объект не удаляется из за того что ссылка повешена на элементе?
Аха.

Цитата:

Но ведь я заменяю сам элемент либо через replaceWith(ajax_result) либо через html(ajax_result) потом запускаю менеджер
Криво, значит, заменяешь. Небось, как-то так?
var ajax_result = $.getJSON("./widgets.json");
$(".widgets").replaceWith(ajax_result);

Цитата:

я Jquery к счастью плохо знаю но мне кажется что много у тебя обработчиков
Не знать серьезно облегчающие жизнь библиотеки можно только к несчастью.

Цитата:

почитай о всплытие !
При чем тут всплытие?

OlegUP 12.02.2015 13:48

я не говорю что я ООП мастер и js ниндзя, даже тут javascript.ru корявые статьи про наследование. Проверил это на своем опыте.

caetus 12.02.2015 13:50

вешаешь одно события и можно легко управлять хоть 100 виджетами !

OlegUP 12.02.2015 13:52

базовый класс:
function Widget(block, options) {
    this.options = eval(options);
    this.block = $(block);
    var self = this;
//    this.options.widget = this.block.attr('widget');

    this.render = function(result_container) {
        if (result_container == undefined) result_container = this.block;
        $.ajax({
            url: "/widget/",
            type: "GET",
            data: {"options": JSON.stringify(this.options) },
            success: function (result) {
                $(result_container).empty().html(result); // empty добавил только что и тестю
                manager.run();
            }
        });
    };

    this.query = function(request_handler) {
    $.ajax({
        url: "/widget/",
        type: "GET",
        data: {"options": JSON.stringify(this.options) },
        success: function (result) {
            request_handler(result);
        }
        });
    };

    this.replaceRender = function() {
        $.ajax({
        url: "/widget/",
        type: "GET",
        data: {"options": JSON.stringify(this.options) },
        success: function (result) {
            self.block.replaceWith(result);
            manager.run()
        }
        });
    };
}

caetus 12.02.2015 13:52

что у тебя виджет делает ? (для интереса )

OlegUP 12.02.2015 13:58

Цитата:

Сообщение от caetus (Сообщение 356367)
что у тебя виджет делает ? (для интереса )

Widget - базовый класс от него наследуются различные классы - списковые(с удалением, добавлением, поиском) загрузка файлов, формирование привязок, виджет текстового поля, скорее всего в следующей версии перейду таки на backbone, спасибо Erolast за совет, хотел попробовать angular, но не стал, времени на то чтобы учить его не было

caetus 12.02.2015 14:00

ясно!!
Erolast я не так понял ))) сори за навязывания ошибочного мнения ))

OlegUP 12.02.2015 14:01

Ну мне все ясно, надо юхать empty() перед заменой, он снимает все хандлеры, спасибо!!!:)

OlegUP 12.02.2015 14:06

Цитата:

Сообщение от caetus (Сообщение 356365)
вешаешь одно события и можно легко управлять хоть 100 виджетами !

Так не выйдет у каждого виджета свои опции, влияющие на его поведение

Erolast 12.02.2015 14:54

Цитата:

тут javascript.ru корявые статьи про наследование.
А? Где? Уверен, что это не ты косячишь?
Цитата:

this.render = function(result_container) {
Не реализуй так методы, у тебя для каждого инстанса будет создаваться собственная пачка функций, что к перерасходу памяти приведет. Используй прототип:
function Person(name) {
  this.name = name;
}
 
Person.prototype.render = function() {
  alert(this.name)
}
 
let person = new Person("Вася");
person.render();

Цитата:

скорее всего в следующей версии перейду таки на backbone,
Переходи заодно и на ECMAScript 6.
Только бэкбон в чистом виде использовать не надо, он реализует лишь самый базовый функционал. К нему нужны довески - гугли Chaplin/Marionette, Rivets.js. И посмотри react.js, может, больше по душе придется.

Цитата:

хотел попробовать angular, но не стал
Ангуляр опасно пробовать. Он идет вразрез с философией JS, что сейчас, при надвигающемся ES6, может быть особо не в тему. С бэкбоном и реактом в этом плане все нормально.

Цитата:

this.options = eval(options);
Опять же, не надо эвал. У тебя там информация в JSON-формате? Используй JSON.parse.


Часовой пояс GMT +3, время: 08:00.