在具有不同延迟的嵌套setTimeout循环之间交替

时间:2013-11-18 18:45:11

标签: javascript jquery delay settimeout jquery-deferred

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

有些php确定将在给定试验中显示的序列并将其传递给JS数组,在那里我遇到两种问题:(1)优雅地处理刺激显示,以及(2)分离“演讲“从”召回“阶段开始。虽然我在这里找到了一些关于这个问题的每一半的有用信息,但是根据我的知识,整合这两个任务已经提出了独特的挑战,这里没有讨论过。所以这里:

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

这部分代码是功能性的,但我无法想象它是最优的。部分并发症是时间间隔不均匀:刺激出现700ms,但它们之前,之间和之后的间隙是500ms。 (很烦人,但是我无法帮助它。)幸运的是,对于我来说,需要提供的东西绝不会超过5件,所以对这些时间戳进行硬编码至少是一个选项,如果不是一个好的话。 / p>

<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
//}

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

HALP?

1 个答案:

答案 0 :(得分: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();
    }
}

此代码将在删除最后一个激励后调用showRecall 500ms,您可以根据自己的需要进行更改,它们仅仅是语句,所以只需在那里插入自己的逻辑。