Вызов jQuery .remove () в обратном вызове запускает бесконечный цикл - PullRequest
1 голос
/ 18 декабря 2009

Хотя у меня сама проблема, казалось бы, решена, я надеюсь, что кто-то может пролить свет на почему этого ...

Ниже приведены два снимка одной и той же функции, работа которых заключается в удалении элемента div, содержащего сообщение обратной связи с пользователем. Он настроен на использование необязательного тайм-аута, если указан тайм-аут, он вызывает сам себя, используя setTimeout (), который затем удаляет div.

Единственное различие между двумя версиями функции заключается в том, что this.remove () вызывается - в версии проблемы я отправляю сообщение в журнал, используя сначала blackbirdjs и затем вызовите this.remove () - после того, как это выполнится, журнал заполняется бесконечными сообщениями журнала «Удаление обратной связи div ...» так быстро, как их может накачать браузер.

В рабочей версии, однако, я просто изменяю порядок, и все работает нормально, и все хорошо ...

Я ошеломлен, я думаю, что порядок в этом случае будет тривиальным, но, очевидно, нет. Может кто-нибудь пролить свет на то, почему это происходит? Это ошибка jQuery или проблема с дроздом или какая-то странная причуда JavaScript вообще?

Примечание:
У меня был некоторый смешанный успех, когда я использовал вызов метода verify () - если он вернулся false, я сказал ему вернуться, и это остановило его - однако, просто добавив return после того, как вызов remove не дал результата.

Интересно, что любая из версий в IE8 работает нормально - так что это может быть проблемой Firefox / Gecko?

Код проблемы:

function clear_feedback(target_container, timeout){
    log.debug("timeout: " + timeout);
    log.debug("target_container: " + target_container);

    if(timeout == undefined){
        log.info("removing target...");

        $(target_container).children(".update_feedback").slideUp("slow",
            function() {
                log.info("Removing feedback div...");
                this.remove();
            }
        );
    }
    else{
        log.info("Setting timeout, THEN removing target...");

        setTimeout("clear_feedback('" + target_container + "')", timeout);
    }
}

Рабочий код:

function clear_feedback(target_container, timeout){
    log.debug("timeout: " + timeout);
    log.debug("target_container: " + target_container);

    if(timeout == undefined){
        log.info("removing target...");

        $(target_container).children(".update_feedback").slideUp("slow",
            function() {
                this.remove();
                log.info("Removing feedback div...");
            }
        );
    }
    else{
        log.info("Setting timeout, THEN removing target...");

        setTimeout("clear_feedback('" + target_container + "')", timeout);
    }
}

Ответы [ 2 ]

1 голос
/ 19 декабря 2009

Вы должны были проверить консоль ошибок браузера, а не полагаться только на консоль blackbirdjs.

Тогда вы бы заметили, что консоль ошибок браузера также переполнена сообщениями об ошибках (с любой из ваших версий кода)

Фактическая проблема в вашем коде

this.remove();

this является элементом HTML DOM в функции обратного вызова и не имеет функции remove(), поэтому дочерние элементы только скрываются, но не удаляются. И на this.remove() вы получите исключение. Когда функция обратного вызова выдает исключение, jQuery попадает в бесконечный цикл, пытаясь выполнить свою работу

Что вам нужно сделать, это обернуть элемент в объект jQuery.

$(this).remove();

Теперь также понятно, почему вторая версия, похоже, исправила ошибку

log.info("Removing feedback div..."); //error logged
this.remove();  //exception

this.remove();  //exception
//log line not executed as previous line threw exception
log.info("Removing feedback div...");

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

Для желающих есть билет с ошибкой

http://dev.jquery.com/ticket/2846

0 голосов
/ 19 декабря 2009

Я видел такую ​​же проблему, но в другом контексте; однако, я подозреваю, что основная причина та же.

Если вы посмотрите на log.info, вы увидите, что он вставляет узел в DOM. Если одна из функций jquery обходит DOM только в правильном месте, в частности, прямо в месте, где log.info вставляет узел, и затем, если это вызывает ваш обратный вызов, ваш обратный вызов вставит другую узел, и вы в конечном итоге в бесконечном цикле.

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

Вы можете попробовать использовать Firebug, расставив точки останова вокруг проблемных линий, а затем просмотреть дерево DOM, чтобы увидеть, можете ли вы определить поведение, подобное этому.

...