【问题标题】:Alternating between nested setTimeout loops with different delays在具有不同延迟的嵌套 setTimeout 循环之间交替
【发布时间】:2013-11-18 18:45:11
【问题描述】:

我正在建立一个基于浏览器的认知心理学实验,它类似于游戏 Simon(但没有 80 年代的风格)。

一些 php 确定将在给定试验中显示的序列并将其传递给 JS 数组,我在其中遇到了两种问题:(1) 优雅地处理刺激显示,以及 (2) 将“呈现”阶段来自“召回”阶段。尽管我在这里找到了一些关于这个问题的每一部分的有用信息,但据我所知,整合这两个任务带来了独特的挑战,这里没有讨论过。所以这里是:

(1) 使用 setTimeouts 一次显示一个数组的内容:

这部分代码是功能性的,但我无法想象它是最优的。部分并发症是时间间隔不均匀:刺激出现 700 毫秒,但之前、之间和之后的间隔为 500 毫秒。 (烦人,但我情不自禁。)对我来说幸运的是,需要呈现的东西永远不会超过 5 件,所以像这样对时间戳进行硬编码至少是一种选择,即使不是一个好选择。

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title></title>

    <style>
            body 
            {color:black}

            table
            {margin: 100px auto 0 auto;
             border: 1;
             text-align:center;

            }
            td
            {
            width: 100px;
            height:100px;
            vertical-align:middle;
            }
            tr:focus 
            { outline: none; }

        </style>
</head>
<body onload="displayStimuli()">

    <table>
        <tr>
            <td id="TopLeft">

            </td>
            <td id="TopMiddle">

            </td>
            <td id="TopRight">

            </td>
        </tr>
        <tr>
            <td id="MiddleLeft">

            </td>
            <td id="MiddleMiddle">

            </td>
            <td id="MiddleRight">

            </td>
        <tr>
            <td id="BottomLeft">

            </td>
            <td id="BottomMiddle">

            </td>
            <td id="BottomRight">

            </td>
        </tr>
        </tr>
    </table>
</body>

<script>

    var stimuli = new Array(1,2,3,4,"*");
    var cells = new Array("TopLeft", "TopRight", "BottomLeft", "BottomRight", "MiddleMiddle");
    var stimOn = new Array(500,1700,2900,4100, 5300) ; //this is a pretty unintelligent solution, but it works!
    var stimOff = new Array(1200,2400,3600,4800, 6000);

            function displayStimuli(){

    for (i=0; i<stimuli.length; i++)
        {

            setTimeout(function (i) {return function(){
                document.getElementById(cells[i]).innerHTML=stimuli[i];
                };
            }(i),stimOff[i]);//when display the next one

            setTimeout(function (i) {return function(){
                document.getElementById(cells[i-1]).innerHTML="";//There will be an error here because for the first item, i-1 is undefined. I can deal.
                };
            }(i),stimOn[i]);//when to remove the previous one
        }

        //showRecall(); //see part (2)!
    } 



</script>

如果有人想想出一个好方法来清理它,请随意!然而,我更棘手的挑战(目前)是下一部分。

(2) 等待调用函数,直到浏览器完成显示之前某个 setTimeout 函数的最终结果。

在这里,我找到了可能是部分解决方案的建议(例如Javascript nested loops with setTimeout),但我无法完全理解如何将它们与我当前的设计集成。从概念上讲,这是我想要发生的事情:

//php sends stimulus array (not including final "*") to js
//js steps through the array, displaying and removing the pictures as above
//after the browser has finished *displaying* the sitmuli in the loop, call a new js function, "recall()".
//recall(){
//this part is fairly straightforward
//}

我看到的一些答案似乎表明使用普通的 ol' js 可以做到这一点,而其他人则坚持认为 jQuery 可以解决问题。我对这两种解决方案都持开放态度,但还没有看到任何适合我的情况的解决方案,其中执行函数的提示不是一定的超时(因为它会随着不同长度的试验而变化),也不是只是等待处理代码,而不是检测浏览器何时完成显示内容。

停下来?

【问题讨论】:

    标签: javascript jquery delay settimeout jquery-deferred


    【解决方案1】:

    这只是一个建议/替代的做事方式,但您可以尝试逐步设置新的超时,而不是使用 for 循环并在未来进一步计算超时,如下所示:

    var stimuli = new Array(1,2,3,4,"*");
    var cells = new Array("TopLeft", "TopRight", "BottomLeft", "BottomRight", "MiddleMiddle");
    
    var alreadyOn = false;
    
    // call startUp on load instead of displayStimuli
    function startUp() {
        setTimeout(displayStimuli, 1200);
    }
    
    function displayStimuli(){
        if(stimuli.length>0) { // if we have any stimuli left
            if(alreadyOn) {
                document.getElementById(cells.shift()).innerHTML="";
                stimuli.shift(); // here we remove elements from the arrays
    
                setTimeout(displayStimuli, 500); // show again in 500ms
            } else {
                document.getElementById(cells[0]).innerHTML=stimuli[0];
    
                setTimeout(displayStimuli, 700); // remove in 700ms
            }
            alreadyOn = !alreadyOn; // flip it for the next round
        } else { // no stimuli left, move on.
            showRecall();
        }
    }
    

    此代码将在删除最后一个刺激后 500 毫秒调用 showRecall,您可以根据自己的需要更改它,它们只是 if 语句,因此只需在其中插入您自己的逻辑即可。

    【讨论】:

    • 完美的解决方案——在各个方面都是理想的。谢谢!特别感谢您以这样一种方式发表评论,我可以很容易地理解代码实际上在做什么!
    • 不客气!编写今天可以工作的代码很容易,编写明天有人可以维护的代码需要小心,而且总是值得付出额外的努力!
    猜你喜欢
    • 2016-11-15
    • 1970-01-01
    • 2012-09-19
    • 1970-01-01
    • 1970-01-01
    • 2017-11-18
    • 2020-12-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多