jQuery .remove()调用回调触发无限循环
虽然我有问题本身似乎已经解决了,但我希望有人可以解释为什么这个……
下面是同一function的两个快照,其作用是删除包含用户反馈消息的div。 它设置为使用可选的超时,如果指定超时,则使用setTimeout()调用自身,然后删除div。
函数的两个版本之间的唯一区别是调用this.remove() – 在问题版本中我首先使用blackbirdjs向日志发送消息然后调用this.remove() – 执行此操作后日志被淹没无尽的日志消息“删除反馈div …”与浏览器可以提取的速度一样快。
然而,在工作版本中,我只是颠倒了顺序,一切都正常执行,一切都很顺利……
我很高兴,我认为这种情况下的顺序是微不足道的,但显然不是。 任何人都可以阐明为什么会发生这种情况? 这是一个jQuery错误或黑鸟的问题或一般的JavaScript奇怪的怪癖?
注意:
我使用调用确认()得到了一些混合成功 – 如果它返回false我告诉它返回并停止它 – 但是,只是在删除调用后添加返回没有效果。
有趣的是,任何一个版本似乎在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); } }
你应该检查你的浏览器错误控制台,而不是仅仅依靠blackbirdjs控制台。
然后你会注意到浏览器错误控制台也充斥着错误消息(使用你的任何一个代码版本)
代码中的实际问题是
this.remove();
this
是回调函数中的HTML DOM元素,并且没有函数remove()
因此子项只会被隐藏但不会被真正删除。 在this.remove()
你得到一个例外。 当回调函数抛出exception时,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的内部工作中进行更深入的调查。 但这对你不感兴趣
对于那些感兴趣的人,有一个真正的错误票
我已经看到了这样的问题,但是在不同的背景下; 但是,我怀疑根本原因是一样的。
如果你看一下log.info,你会发现它将一个节点插入到DOM中。 如果其中一个jquery函数恰好在正确的位置遍历DOM,特别是在log.info插入节点的位置,然后如果这导致调用回调,则回调将插入另一个节点,你最终陷入无限循环。
为什么在IE8中不会发生这种情况的问题可能是两个原因之一:要么跨浏览器的DOM结构不完全相同,要么IE8在javascript代码遍历时使用不同的策略来处理DOM节点插入树。
您可以尝试使用Firebug,在有问题的行周围放置一个断点,然后查看DOM树以查看是否可以发现这样的行为。