简体   繁体   English

我可以在另一个 setTimeout 的处理程序中有一个 setTimeout 吗?

[英]Can I have a setTimeout inside a handler of another setTimeout?

Here's a quick (broke) jsfiddle: http://jsfiddle.net/wH2qF/这是一个快速(损坏)的 jsfiddle:http: //jsfiddle.net/wH2qF/

This isn't working for some reason... is it because I have a setTimeout inside a handler of another setTimeout?由于某种原因这不起作用......是因为我在另一个 setTimeout 的处理程序中有一个 setTimeout 吗?

$(function() {
   $("#Volume").click(function() {
      setTimeout(triggerVolumeChange, 4000);
      function triggerVolumeChange() 
      {
          var volumeDiv = document.getElementById("volumeNumber");
          var volumeOld = 8;
          var volumeNew = 37;
          var timeNew = (1000/(volumeNew-volumeOld));
          changeVolume();
                        
          function changeVolume()
          {
             volumeDiv.innerHTML = volumeOld;
             volumeOld++;
             if (volumeOld <= volumeNew) setTimeout(changeVolume, timeNew);
          };
      });
});

Should specify that for clarity purposes I deleted other things from that Click function, and also to clarify what doesn't work exactly, well, basically, I click and nothing happens, whereas if I cut out this chunk of code it works fine... actually the setting of the vars also work fine (naturally I presume) but when I paste or uncomment the changeVolume() function then the click stops working again... Any thoughts?应该明确指出,为了清楚起见,我从该 Click 函数中删除了其他内容,并澄清了哪些内容不能正常工作,好吧,基本上,我点击但没有任何反应,而如果我删除这段代码,它就可以正常工作。 . 实际上 vars 的设置也工作正常(我自然认为)但是当我粘贴或取消注释 changeVolume() 函数时,点击再次停止工作......有什么想法吗?

-- --

Another piece of clarification: What I'm trying to do is, on click, simulate the volume going from value 8 to 37, in a string.. thus the setTimeout inside that function.另一个澄清:我想做的是,在单击时,模拟从值 8 到 37 的音量,在一个字符串中......因此是该函数中的 setTimeout。

-- --

As per your guy's request, here's the entire code... I doubt it will make sense, but here it is... FYI, on click this will trigger a number of animations to simulate the flow of an application I'm designing..按照你的人的要求,这里是完整的代码......我怀疑它是否有意义,但它是......仅供参考,单击它会触发许多动画来模拟我正在设计的应用程序的流程。 .

<script>
            $(function() {
                $("#Volume").click(function() {
                                        
                    var userPrompt = document.getElementById("userPrompt")
                    userPrompt.innerHTML = "Change volume to 37";
                                        
                    var avatarIcon = document.getElementById("avatarIcon");
                    avatarIcon.innerHTML = "<img src='imgs/haloIcons-volume_82x76.png' alt='Volume'/>";
                
                    var hints = document.getElementById("hints");
                    hints.style.opacity = 0;
                    $(".dragonTvOut").toggleClass("dragonTvIn");
                    
                    setTimeout(triggerP, 1000);
                    function triggerP()
                    {
                        var halo = document.getElementById('avatar');
                        if( 'process' in halo ) { 
                            halo.process();
                        };
                    };
                    
                    setTimeout(triggerUserPrompt, 2000);
                    function triggerUserPrompt() 
                    {
                        document.getElementById("userPrompt").className = "userPromptIn";
                    };
                    
                    setTimeout(triggerVolumeChange, 4000);
                    function triggerVolumeChange() 
                    {
                        document.getElementById("userPrompt").className = "userPromptEnd";
                        
                        var halo = document.getElementById('avatar');
                        if( 'resume' in halo ) { 
                            halo.resume();
                        }

                        document.getElementById("avatarIcon").className = "avatarIconEnd";
                        
                        var volumeDiv = document.getElementById("volumeNumber");
                        var volumeOld = 8;
                        var volumeNew = 37;
                        var timeNew = (1000/(volumeNew-volumeOld));
                        changeVolume();
                        
                        function changeVolume()
                        {
                            volumeDiv.innerHTML = volumeOld;
                            volumeOld++;
                            if (volumeOld <= volumeNew) setTimeout(changeVolume, timeNew);
                        }​;
                        
                        var side = 100;
                        var paper = new Raphael(volumeArcAnim, 100, 300);
                        
                        paper.customAttributes.arc = function (xloc, yloc, value, total, R) {

                            var alpha = 360 / total * value,
                                a = (90 - alpha) * Math.PI / 180,
                                x = xloc + R * Math.cos(a),
                                y = yloc - R * Math.sin(a),
                                path;
                            if (total == value) {
                                path = [
                                    ["M", xloc, yloc - R],
                                    ["A", R, R, 0, 1, 1, xloc - 0.01, yloc - R]
                                ];
                            } else {
                                path = [
                                    ["M", xloc, yloc - R],
                                    ["A", R, R, 0, +(alpha > 180), 1, x, y]
                                ];
                            }
                            return {
                                path: path
                            };
                        };
                    
                        var arcWidth = 87;
                        var strokeRadius = arcWidth/2;
                        
                        var indicatorArc = paper.path().attr({
                            "stroke": "#ffffff",
                            "stroke-width": 3,
                            arc: [side/2, side/2, 12, 100, strokeRadius]
                        });
                        
                        indicatorArc.animate({
                            arc: [side/2, side/2, 60, 100, strokeRadius]
                        }, 1500, "<>", function(){
                            // anim complete here
                        });
                        
                    };
                                            
                });
            });
            </script>

Yes, you can have a setTimeout() inside another one -- this is the typical mechanism used for repeating timed events.是的,您可以在另一个内部设置一个setTimeout() ——这是用于重复定时事件的典型机制。

The reason yours isn't working is not to do with the setTimeout() itself;您不工作的原因与setTimeout()本身无关; it's to do with the way you've nested the functions.这与您嵌套函数的方式有关。

The changeVolume() function being inside triggerVolumeChange() means that you can't reference it directly using its name. changeVolume()函数位于triggerVolumeChange()内,这意味着您无法使用其名称直接引用它。

The quickest solution for you would be to remove the nesting, so that changeVolume() is at the root level rather than nested inside triggerVolumeChange() .最快的解决方案是删除嵌套,以便changeVolume()位于根级别而不是嵌套在triggerVolumeChange()中。

You're missing an } :你错过了一个}

$(function() {
   $("#Volume").click(function() {
      setTimeout(triggerVolumeChange, 4000);
      function triggerVolumeChange()
      {
          var volumeDiv = document.getElementById("volumeNumber");
          var volumeOld = 8;
          var volumeNew = 37;
          var timeNew = (1000/(volumeNew-volumeOld));
          changeVolume();

          function changeVolume()
          {
             volumeDiv.innerHTML = volumeOld;
             volumeOld++;
                 if (volumeOld <= volumeNew) setTimeout(changeVolume, timeNew);
          };
      } // that one was missing
   });
});

In your broken example http://jsfiddle.net/wH2qF/ there are a few problems在你坏掉的例子中http://jsfiddle.net/wH2qF/有一些问题

  • You forgot to tell jsfiddle to use jQuery你忘了告诉 jsfiddle 使用 jQuery
  • The id of the volume span (in JS) was ph but should be volumeNumber (as in the HTML)卷跨度的 id(在 JS 中)是ph但应该是volumeNumber (如在 HTML 中)

Click here to see a working version单击此处查看工作版本

Had you selected jQuery from the libraries in jsfiddle, you would have seen an error如果你从 jsfiddle 的库中选择了 jQuery,你会看到一个错误

Uncaught TypeError: Cannot set property 'innerHTML' of null未捕获的类型错误:无法设置 null 的属性“innerHTML”

That leads me to believe that your jsfiddle is not a good representation of your problem.这使我相信您的 jsfiddle 不能很好地代表您的问题。 Maybe try to create another reduction since the one you added only had "silly" errors?也许尝试创建另一个减少,因为您添加的那个只有“愚蠢”的错误?

If you don't want to use setInterval() , you can make the code work with these changes:如果您不想使用setInterval() ,您可以使代码适用于这些更改:

$(function() {
    $("#Volume").click(function() {
        setTimeout(triggerVolumeChange, 4000);
        function triggerVolumeChange () {
            var volumeDiv = document.getElementById("volumeNumber");
            var volumeOld = 8;
            var volumeNew = 37;
            var timeNew = (1000/(volumeNew-volumeOld));
            var changeVolume = function () {
                volumeDiv.innerHTML = volumeOld;
                volumeOld++;
                if (volumeOld <= volumeNew) setTimeout(changeVolume, timeNew);
            };
            changeVolume();
        }
    });
});

Working demo at jsFiddle . jsFiddle的工作演示。

Technically there is no difference where the timer is initiated from.从技术上讲,计时器的启动位置没有区别。 In most cases it is implemented as list of the timers with an identifiers and associated callback handlers.在大多数情况下,它被实现为带有标识符和关联回调处理程序的计时器列表。

So it will be ok if your logic is correct.所以如果你的逻辑正确就可以了。 There is no unpredictable conditions that bring infinite call sequences, and there is no infinite amount of timeout instances and so on.没有不可预知的条件带来无限的调用序列,也没有无限量的超时实例等等。

For example imitation of setInterval function:例如模仿setInterval函数:

// Bad (unexpected multiple sequences started per each event)

const handler = () => {
  setTimeout(handler)
}

<Button onClick={handler} />
// Good (previous interval closed before start new one)

const [id, idUpdate] = useState(-1)

const handler = () => {
  const id = setTimeout(handler)
  idUpdate(id)
}

const start = () => {
  if(id !===-1) clearTimeout(id)
  idUpdate(-1)
  handler()
}

<Button onClick={start} />

or some else或其他人

// Bad (infinite events with small time will take all cpu time)

const handler = () => {
  setTimeout(handler, 0) // actually mean several ms
}
// Good (special condition for finish iterations)

let count = 20

const handler = () => {
  if(!count) return
  count--
  setTimeout(handler, 0)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM