在循环锁定浏览器时暂停执行(用fiddles更新)



我知道我的问题,只是不知道如何解决。我有一个自定义域,在函数调用中执行while循环。在那个循环中,我希望动画按顺序出现。

因此,第一个问题是javascript本质上执行每一行,因此第2项在第1项完成之前开始。现在效果是如此之短,以至于它"似乎"同时发生在所有元素上,但在调试器中,它只是一次循环一个。

现在,我的典型解决方案是使用SetTimeout(),但这会导致浏览器锁定。阅读这篇文章(试图在jQuery中延迟/暂停/减慢while循环),浏览器进入无休止的循环是有道理的。

那么,如何在element1和element2事件之间获得暂停呢?我想也许可以在我的自定义域中添加一个回调函数,但除了不确定如何做到之外,我不确定这是否会如预期的那样工作

在页面的顶部阅读评论,了解我可能做错了什么或可以做得更好。

$(document).ready(function ()
{
    //pause long enough for person to visually take in page before starting
    setTimeout(function () { PageLoadAnimation.onReady(); }, 1000);
});

我的自定义域:

var PageLoadAnimation = 
{
    onReady: function ()
    {
        //black everything out just to be sure
        PageLoadAnimation.BlackOutElements();
        //flash & show
        PageLoadAnimation.FlashElement();
    },
    BlackOutElements: function ()
    {
        $('#ParentContainer').children().hide();
    },
    FlashElement: function ()
    {
        //get array of all elements and loop till all are visible
        var elementArray = $('#ParentContainer').children();
        var $els = $('#PartialsContainer').children();
        while (elementArray.length)
        {
           var $el = elementArray.eq(Math.floor(Math.random() * elementArray.length));
           //if I put set timeout here is causes the infinite loop
           PageLoadAnimation.FlashBlast($el);
           elementArray = elementArray.not($el);
           //if I put by itself it no diff as the while loop continues regardless
           //setTimeout(1500);

        }
    },
    FlashBlast: function ($el)
    {
       //flash background
       $el.fadeIn(200, function () { $el.fadeOut(200) });
    }
}

我不确定它是不起作用,还是我做错了什么,所以我创建了这些小提琴:

原始Fiddle

与Johan Callbacks

使用是设置属性的动画警告这个会挂起你的浏览器!我不认为我在像Johan想的那样检查isAnimating属性??


回答这种情况。希望它能帮助其他人

循环中的setTimeout确实是我的问题。。。但不是唯一的问题。我是另一个问题。

我先。

我真是个傻瓜,我做错了两件事,这真的让我自己陷入了困境。

首先使用jsfiddle,我的javascript会因为语法或诸如此类的事情而出错,但fiddle没有告诉你(据我所知),所以我的fiddle不会运行,但我很自豪,因为我的代码很好,愚蠢的javascript不起作用。

第二,我错误地将函数传递给了setTimeout。我添加了函数parens(),这也不正确,这会让我回到上面的问题。

WRONG: intervalTimer = setInterval(MyFunction(), 1500);
RIGHT: intervalTimer = setInterval(MyFunction, 1500);

至于我在这里读到的代码(http://javascript.info/tutorial/settimeout-setinterval)在循环中设置超时是不好的。循环将快速迭代,超时是循环中的一个步骤,我们将进入循环射击队。

这是我的实现:

我创建了几个变量,但不希望它们污染全局范围,所以我在自定义域中创建了它们。一个用于保存元素数组,另一个用于setInterval对象的句柄。

var PageLoadAnimation =
               {
                   elementArray: null,
                   intervalTimer: null,
                   ....
                }

在我的onReady函数(页面调用它来启动)中,我设置了域数组变量,并设置了保存句柄的间隔,以备以后使用。请注意,间隔计时器是图像闪烁之间的间隔时间。

onReady: function () 
      {
         elementArray = $('#PartialsContainer').children();
         //black everything out just to be sure
         PageLoadAnimation.BlackOutElements();
         //flash & show
         intervalTimer = setInterval(PageLoadAnimation.FlashElement, 1500);
       },

现在,我不是在数组中循环,而是以特定的间隔执行一个函数,并跟踪数组中还有多少元素需要闪烁。一旦数组中有零个元素,我就会终止间隔执行。

FlashElement: function () 
{
   if(elementArray.length > 0) //check how many elements left to be flashed
   {
      var $el = PageLoadAnimation.GrabElement(); //get random element
      PageLoadAnimation.FlashBlast($el); //flash it
      PageLoadAnimation.RemoveElement($el); //remove that element
   }
   else
   {
      //done clear timer
      clearInterval(intervalTimer);
      intervalTimer = null;
   }

},

所以整件事就是:

var PageLoadAnimation =
               {
                   elementArray: null,
                   intervalTimer: null,
                   onReady: function () {
                       elementArray = $('#PartialsContainer').children();
                       //black everything out just to be sure
                       PageLoadAnimation.BlackOutElements();
                       //flash & show
                       intervalTimer = setInterval(PageLoadAnimation.FlashElement, 1500);
                       //NOT this PageLoadAnimation.FlashElement()
                   },
                   BlackOutElements: function () {
                       $('#PartialsContainer').children().hide();
                   },
                   FlashElement: function () 
                   {
                       if(elementArray.length > 0)
                       {
                           var $el = PageLoadAnimation.GrabElement();
                           PageLoadAnimation.FlashBlast($el);
                           PageLoadAnimation.RemoveElement($el);
                       }
                       else
                       {
                           //done clear timer
                           clearInterval(intervalTimer);
                           intervalTimer = null;
                       }

                   },
                   GrabElement: function()
                   {
                       return elementArray.eq(Math.floor(Math.random() * elementArray.length));
                   },
                   RemoveElement: function($el)
                   { elementArray = elementArray.not($el); },
                   FlashBlast: function ($el) {
                       //flash background
                      $el.fadeIn(100, function () { $el.fadeOut(100) });
                   }

               }

希望能帮助其他人理解如何在javascript中暂停执行。

一个可能有帮助的回调示例:

FlashBlast: function ($el, fadeInComplete, fadeOutComplete)
{
   if(arguments.length === 3){
       $el.fadeIn(200, function () {
           fadeInComplete();
           $el.fadeOut(200, fadeOutComplete);
       });
   }
}

用法:

PageLoadAnimation.FlashBlast($el, function(){
    //fadein complete
}, function(){
    //fadeout complete
});

另一个可能有帮助的想法:

 isAnimating: false,
 FlashBlast: function ($el)
 {
     var dfd = $.Deferred(),
         that = this;
     that.isAnimating = true;
     $el.fadeIn(200, function () { 
         $el.fadeOut(200, function(){
             dfd.resolve();
         }) 
     });
     dfd.done(function(){
         that.isAnimating = false;
     });
 }

然后利用私有财产CCD_ 1。

最后,要知道元素是否在动画下,可以使用$el.is(':animated')

希望这能有所帮助。如果有什么不清楚的地方,请告诉我。

最新更新