javascript - 错误的算法触发并发循环

发布于 2024-12-03 21:17:56 字数 2315 浏览 1 评论 0原文

我创建了一个相对较小的动态横幅旋转脚本,底部带有图标,用于使特定横幅成为焦点。在横幅上按下鼠标输入键会暂停显示,但有时当我将鼠标从横幅上移开时,某些横幅的延迟会缩短。我什至可以理解,如果它只发生一次,但每次横幅在轮换中返回时,延迟都会设置为更短的时间,并且缩短通常发生在横幅列表中的另一个位置,如出色地。有时,这可以通过一组尚未确定的行动来纠正。我开始怀疑我的逻辑在中间某处捕获了循环,因此进程分支,运行两个循环,这似乎加快了 showNextBanner 函数的调用速度。不知道如何解决这个问题。我已经进行了测试,看看它当前是否处于播放模式,但无济于事。

我包含了我认为以下代码的相关部分。

        var firstRun = true;
        var play = true;
        var current = 0;

        var banners = $$( '.banner' ); 
        banners.invoke( 'hide' );
        var images = $$( '.image' );
        var icons = $$( '.icon' );
        //dynamically clones an initial icon to match the number of banners
        initIcons();

        banners.invoke( 'observe', 'mouseenter', function( field ) {
            play = false;
        });

        banners.invoke( 'observe', 'mouseleave', function( field ) {
            if( !play ) {
                play = true;
                showNextBanner().delay(3);
            }
        });

        icons.invoke( 'observe', 'click', function( field ) {
                play = false;
                hideBanner( current );
                showBanner( findObj( icons, field.findElement()));
        });


        showNextBanner().delay(3); 


        function hideBanner( which ) {
            icons[ which ].src = blankIconSRC;
            banners[ which ].hide();
        }


        function showBanner( which ) {
            icons[ which ].src = selectedIconSRC;
            banners[ which ].show();
            current = which;
        }


        // loops the hiding and showing of icons 
        // (mouseenter sets play to false)
        function showNextBanner() {
            if( play ) {
                if( !firstRun ) {
                    if( ++current == banners.length ) current = 0;    
                    var previous = 0;
                    ( current == 0 )? previous = banners.length - 1: previous = current - 1;
                    hideBanner( previous );
                } else {
                    icons[0].src = selectedIconSRC;
                    firstRun = false;
                }
                showBanner( current );
                showNextBanner.delay(3);
            }
        }
    }());

毕竟,客户想要一个 jQuery 解决方案,这样他就可以获得通过 scriptaculous 无法获得的滑入效果。所以所有的工作都白费了。好消息是我可以只使用 jCarousel,并调整样式表。感谢您的帮助!

I created a relatively small dynamic banner rotation script with icons at the bottom for bringing a particular banner into focus. Firing a mouseenter over a banner pauses the show, but sometimes when I mouseout from my banner, the delay for certain banners gets shortened. I'd even understand if it just happened once, but the delay is then set for that shorter amount of time every time the banner comes back around in the rotation, and often the shortening happens in one other place in the list of banners, as well. Sometimes this can be corrected by an as yet undetermined set of actions. I'm starting to suspect that my logic is catching the loop in the middle somewhere and so the process branches out, runs two loops, which appear to speed up the calling of the showNextBanner function. Not sure how to solve this. I've put in tests to see if it's currently in play mode, to no avail.

I include what I think are the relevant parts of the code below.

        var firstRun = true;
        var play = true;
        var current = 0;

        var banners = $( '.banner' ); 
        banners.invoke( 'hide' );
        var images = $( '.image' );
        var icons = $( '.icon' );
        //dynamically clones an initial icon to match the number of banners
        initIcons();

        banners.invoke( 'observe', 'mouseenter', function( field ) {
            play = false;
        });

        banners.invoke( 'observe', 'mouseleave', function( field ) {
            if( !play ) {
                play = true;
                showNextBanner().delay(3);
            }
        });

        icons.invoke( 'observe', 'click', function( field ) {
                play = false;
                hideBanner( current );
                showBanner( findObj( icons, field.findElement()));
        });


        showNextBanner().delay(3); 


        function hideBanner( which ) {
            icons[ which ].src = blankIconSRC;
            banners[ which ].hide();
        }


        function showBanner( which ) {
            icons[ which ].src = selectedIconSRC;
            banners[ which ].show();
            current = which;
        }


        // loops the hiding and showing of icons 
        // (mouseenter sets play to false)
        function showNextBanner() {
            if( play ) {
                if( !firstRun ) {
                    if( ++current == banners.length ) current = 0;    
                    var previous = 0;
                    ( current == 0 )? previous = banners.length - 1: previous = current - 1;
                    hideBanner( previous );
                } else {
                    icons[0].src = selectedIconSRC;
                    firstRun = false;
                }
                showBanner( current );
                showNextBanner.delay(3);
            }
        }
    }());

After all that, the client wants a jQuery solution so he can have a slide-in effect not available via scriptaculous. So all that work is down the drain. The good news is that I can just use jCarousel, probably, and tweak the stylesheet. Thanks for the help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

紫瑟鸿黎 2024-12-10 21:17:56

我怀疑发生的情况是您有多个 .delay 调用堆积起来。因此,您的时间还剩不到 3 秒,并且再次调用 showNextBanner,设置另一个延迟计时器。

当我阅读文档时,.delay 似乎是为了在 jquery 事件管道中放置间隙,而不是实际延迟函数调用。您可能会受益于切换到调用 setTimeout 而不是延迟,这样您就可以获得超时的句柄,然后您可以在设置新超时之前取消该句柄(或者如果播放设置为 false 则取消,然后当播放再次为 true 时重置) .delay 的 JQuery 文档 中提到了这一点

I suspect what is happening is that you've got multiple .delay calls stacking up. So you've got one with less than 3 seconds remaining and showNextBanner is called again, setting another delay timer.

As I read the docs, it appears .delay is intended to put gaps in the jquery event pipeline, rather than actually delay function calls. You may benefit from switching to calling setTimeout instead of delay, so that you get a handle to the timeout, which you can then cancel before setting a new timeout (or cancel if play is set to false, then reset when play is true again) This is mentioned in the JQuery docs for .delay

魂牵梦绕锁你心扉 2024-12-10 21:17:56

我的猜测是,由于您没有“取消”delay() 的函数,因此它们会停留太久,但它们在触发时不会执行任何操作,因为 play 是错误的。但一旦 play 再次为 true,所有内容都会再次开始生效。

您可以保存 delay() 返回的值,并使用 clearTimeout() 和该值取消计时器。

但是,我还建议您对所有横幅使用单个容器(也许也将图标放在那里),并设置 mouseenter/mouseleave 事件在此基础上,而不是单独的横幅上。然后只有一个元素可以启动/停止横幅旋转。如果您还将所有内容拆分为播放和停止旋转的特定函数,以及显示特定横幅的函数,则可能会获得更清晰的代码结构。

这是一个示例(这只是我为了好玩而组合在一起的东西,而不是对代码的编辑,所以它是很不同。抱歉,但希望你仍然可以使用它)

My guess is that since you don't "cancel" the delay()'ed function, they hang around for too long, but they don't do anything when they fire, because play is false. But once play is true again, the all start having an effect again.

You can save the returned value for delay() and cancel the timer by using clearTimeout() with the value.

However, I'd also suggest that you use a single container for all the banners (and maybe put the the icons in there too), and set the mouseenter/mouseleave events on that, rather than on individual banners. Then there's just a single element that'll start/stop the banner rotation. If you also split everything up in specific functions that play and stop the rotation, and one to show a specific banner, you can possibly get a cleaner code structure.

Here's an example (it's just something I put together for fun rather than an edit of your code, so it's quite different. Sorry. But hopefully you can still use for something)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文