一次执行函数后,SetTimeout停止

时间:2014-02-03 01:57:19

标签: javascript jquery

实际上,这是在尝试回答另一个问题时创建的问题:https://stackoverflow.com/questions/21517910/remove-elements-in-reverse-order/

我提供了伪代码和Derek朕会功夫提供的代码。但是,当我想为代码添加一个短暂的延迟时,我们可以看到发生了什么,它会停止正常执行。 SetTimeOut在执行一次后停止。

小提琴:http://jsfiddle.net/UFfHX/

JQuery代码:

function RemoveNode(node) {
    for (var i = node.children.length - 1; i >= 0; i--) {
       setTimeout(RemoveNode(node.children[i]));
    }
    $(node).remove();
}

RemoveNode($(".parent")[0]);

我尝试使用window.setTimeout()并使用function(){}内部调用删除节点,但它不起作用。同时,此代码正确执行:

function RemoveNode(node){
    for(var i = node.children.length - 1; i >= 0; i--){
      RemoveNode(node.children[i]);
        alert("hi");
    }
    $(node).remove();
}

RemoveNode($(".parent")[0]);

编辑: 为了澄清,我想在下面的示例中每次调用RemoveNode之前添加2s等待。

function RemoveNode(node) {
    for (var i = node.children.length - 1; i >= 0; i--) {
       //Something like sleep(2000);
       RemoveNode(node.children[i]);
    }
    $(node).remove();
}

RemoveNode($(".parent")[0]);

2 个答案:

答案 0 :(得分:3)

如果您要做的是慢慢删除DOM子项,那么这里有一个如何使用计时器执行此操作的简单示例:

function removeSlowly() {
    function removeNext() {
        var item = $("#top li:last").remove();
        if (item.length) {
            setTimeout(removeNext, 1000);
        }
    }
    removeNext();    
}

关于您当前代码的评论:

您必须将函数引用传递给setTimeout(),并且必须传递时间值作为第二个参数,并且必须具有正确数量的匹配的parens。

所以,改变这样的代码:

setTimeout(RemoveNode(node.children[i]);

为:

setTimeout(function() {
    RemoveNode(node.children[i]);
}, 1000);

当你试图传递RemoveNode(node.children[i])时,你正在立即执行该函数(这是parens所做的),然后将返回结果传递给setTimeout()。由于返回值不是函数,因此`setTimeout()没有任何内容可以只调用一次函数。

仅供参考,您还有各种语法错误(缺少参数和缺少参数),因此您需要在代码的其余部分中清除所有这些错误。


此外,即使您在此处修复了setTimeout()代码,也存在以下几个逻辑问题:

function RemoveNode(node) {
    for (var i = node.children.length - 1; i >= 0; i--) {
       setTimeout(function() {
           RemoveNode(node.children[i]);
       }, 1000);
    }
    $(node).remove();
}

首先,i回调函数中setTimeout()的值不正确,因为 for循环已经完成执行,因此i将在循环结束时具有值。这可以通过闭包修复。

然后,在您已经删除了父级后,您正尝试在子级上调用RemoveNode()。那是什么意思?孩子们已经从DOM中删除了。

您可以使用i这样解决问题,但我不确定在已经从DOM中删除子项时,对子项调用RemoveNode是什么意思。

function RemoveNode(node) {
    for (var i = node.children.length - 1; i >= 0; i--) {
       (function(index) { 
           setTimeout(function() {
               RemoveNode(node.children[index]);
           }, 1000);
       })(i);
    }
    $(node).remove();
}

答案 1 :(得分:1)

要补充jfriend00已经说过的内容,这一切都是正确的,您可能需要查看以下内容: jsfiddle

我不确定你想要删除dom的程度以及删除工作方式的确切意图,但这将每两秒删除一次叶节点和一个父节点。它显示了如何使用setTimeout和递归。

    var interval = 2000;
    function RemoveNode($node) {  
        if( $node.children().length > 0 )
        {
            $node.children().each(function(){                       
               RemoveNode($(this));        
            });
        }
        else
        {              
            setTimeout(
                function()
                {                                               
                    var $parent = $node.parent();
                    $node.remove();
                    if( $parent.children().length == 0 )
                    {                       
                       $parent.remove();
                    }
                }, 
                interval
            ); 
            interval += 2000;        
        }
    }
    RemoveNode($(".parent"));

<强>更新

请参阅: jsfiddle

如果元素具有removable类,则会逐个删除这些元素。 removable类不会删除树中的每个元素,例如liul。如果您希望两个父项并行删除,请从代码中取出.first()

var interval = 2000;
function RemoveNode($node) { 
    var $removable = $node.find('.removable').first();
    if( $removable.length > 0 )
    {
         RemoveNode($removable);
    }
    else if( $node.hasClass('topParent') == false )
    {          
        //this is a leaf removable node.
        setTimeout(
            function()
            {                                         
                var $parent = $node.parent().closest('.removable');                                
                $node.remove();
                RemoveNode($parent);                
            }, 
            interval
        );                      
    }
}
RemoveNode($(".topParent"));

HTML:

<div class="topParent removable">
    <div class="parent removable">
        <div class="second removable">
            <div class="third removable">
                <ul class="removable">
                    <li>Hey</li>
                </ul>
                <ul class="removable">
                    <li>Hey 1</li>
                </ul>
                <ul class="removable">
                    <li>Hey 2</li>
                </ul>
            </div>
        </div>
    </div>
    <div class="parent removable">
        <div class="second removable">
            <div class="third removable">
                <ul class="removable">
                    <li>Hey</li>
                </ul>
                <ul class="removable">
                    <li>Hey 1</li>
                </ul>
                <ul class="removable">
                    <li>Hey 2</li>
                </ul>
            </div>
        </div>
    </div>
</div>