有没有比下面的pausecomp函数(取自此处)更好的方法来设计JavaScript中的睡眠?

function pausecomp(millis)
{
    var date = new Date();
    var curDate = null;
    do { curDate = new Date(); }
    while(curDate-date < millis);
}

这不是JavaScript中的Sleep的重复-动作之间的延迟;我希望在函数的中间有一个真正的睡眠,而不是在代码执行之前有一段延迟。


当前回答

如果你喜欢建议,不要失去表现。setTimeout是您的预期睡眠。然而,如果您需要一种语法,其中代码被睡眠“中间分割”,我们可以这样做:

sleep = function(tm, fn){
   window.setTimeout(fn, tm);
}

然后,准备如下功能:

var fnBeforeSleep = function(){

  // All code before sleep

}

var fnAfterSleep = function(){

  // All code after sleep

}

然后:

fnBeforeSleep();
sleep(2000, fnAfterSleep);

// Yep! Syntactically, it is very close to:

fnBeforeSleep();
sleep(2000);
fnAfterSleep();

其他回答

在Firebug(可能还有其他JavaScript控制台)中,只有在指定的睡眠时间(…)之后,点击enter后才会发生任何事情

function sleepFor(sleepDuration){
    var now = new Date().getTime();
    while(new Date().getTime() < now + sleepDuration){ /* Do nothing */ }
}

使用示例:

函数sleepFor(sleepDuration){var now=new Date().getTime();而(newDate().getTime()<now+sleepDuration){/*什么都不做*/}}函数sleepThenAt(){sleepFor(2000);console.log(“您好,JavaScript睡眠!”);}sleepThenAt()

注:仅用于调试和开发

如果你写一个这样的睡眠函数

var sleep = function(period, decision, callback){
    var interval = setInterval(function(){
        if (decision()) {
            interval = clearInterval(interval);
            callback();
        }
    }, period);
}

你有一个异步函数可以多次调用,

var xhr = function(url, callback){
    // Make an Ajax request
    // Call a callback when the request fulfils
}

您的项目设置如下:

var ready = false;

function xhr1(){
    xhr(url1, function(){ ready = true;});
}
function xhr2(){
    xhr(url2, function(){ ready = true; });
}
function xhr3(){
    xhr(url3, function(){ ready = true; });
}

然后您可以执行以下操作:

xhr1();
sleep(100, function(){ return done; }, xhr2);
sleep(100, function(){ return done; }, xhr3);
sleep(100, function(){ return done; }, function(){
    // Do more
});

而不是像这样无休止的回调缩进:

xhr(url1, function(){
    xhr2(url2, function(){
        xhr3(url3, function(){
            // Do more
        });
    });
});

2009年的一个老问题。2015年,ECMAScript 2015 AKA ES6中定义的生成器可以提供新的解决方案。它于2015年6月获得批准,但之前已在Firefox和Chrome中实现。现在,休眠功能可以在不冻结浏览器的情况下,在循环和子函数中进行非繁忙、非阻塞和嵌套。只需要纯JavaScript,不需要库或框架。

下面的程序显示了sleep()和runSleepyTask()是如何实现的。sleep()函数只是一个yield语句。它非常简单,实际上直接编写yield语句比调用sleep()更容易,但这样就不会有sleep单词了:-)yield返回一个时间值给wakeup()内的next()方法并等待。实际的“睡眠”是使用旧的setTimeout()在wakeup()中完成的。在回调时,next()方法触发yield语句继续,yield的“魔力”在于所有局部变量及其周围的整个调用堆栈仍然完好无损。

使用sleep()或yield的函数必须定义为生成器。这很容易通过在关键字函数*中添加星号来实现。执行生成器有点棘手。当使用关键字new调用时,生成器返回一个具有next()方法的对象,但不执行生成器的主体(关键字new是可选的,没有任何区别)。next()方法触发生成器主体的执行,直到遇到产量。包装函数runSleepyTask()启动乒乓球:next()等待yield,yield等待next(()。

另一种调用生成器的方法是使用关键字yield*,这里它的工作方式类似于一个简单的函数调用,但它还包括返回next()的能力。

示例drawTree()演示了这一切。它在旋转的3D场景上绘制了一棵带有树叶的树。一棵树被画成树干,顶部有三个不同方向的部分。在短暂的睡眠后,通过递归调用drawTree(),将每个部分绘制为另一个较小的树。一棵很小的树被画成一片叶子。

每个叶子在一个单独的任务中都有自己的生命,该任务以runSleepyTask()开始。它在growtLeaf()中出生、生长、静止、褪色、坠落和死亡。速度由sleep()控制。这证明了多任务处理是多么容易。

函数*sleep(毫秒){yield毫秒};函数runSleepyTask(任务){(函数唤醒(){var result=task.next();if(!result.done)setTimeout(唤醒,result.value);})()}////////////////作者:Ole Middelboe/////////////////////////////pen3D=setup3D();var taskObject=新绘图树(pen3D.center,5);runSleepyTask(taskObject);函数*drawTree(root3D,大小){如果(size<2)运行SleepyTask(new-growLeaf(root3D))其他{pen3D.drawTrunk(root3D,大小);for(变量p为[1,3,5]){var part3D=新pen3D.Thing;root3D.add(part3D);part3D.移动(尺寸).转动(p).倾斜(1-p/20);产量*睡眠(50);产量*drawTree(part3D,(0.7+p/40)*尺寸);}}}函数*growtLeaf(stem3D){var leaf3D=pen3D.drawLeaf(stem3D);对于(var s=0;s++<15;){yield*sleep(100);leaf3D.scale.multiplyScalar(1.1)}yield*sleep(1000+9000*Math.random());对于(var c=0;c++<30;){yield*sleep(200);leaf3D.sskin.color.setRGB(c/30,1-c/40,0)}对于(var m=0;m++<90;){yield*sleep(50);leaf3D.turn(0.4).tilt(0.3).move(2)}leaf3D.visible=false;}///////////////////////////////////////////////////////////////////////函数setup3D(){var场景,相机,渲染器,directionalLight,pen3D;scene=新的THREE.scene();相机=新的三个透视相机(75,window.innerWidth/window.innerHeight,0.1,1000);相机位置设置(0,15,20);renderer=new THREE.WebGLRenderer({alpha:真,抗锯齿:真});renderer.setSize(window.innerWidth,window.innerHeight);document.body.appendChild(render.domElement);directionalLight=新的三个。directionalLight(0xffffaa,0.7);directionalLight.position.set(-1,2,1);scene.add(directionalLight);scene.add(新的THREE.AmbientLight(0x9999ff));(函数render(){requestAnimationFrame(渲染);//renderer.setSize(window.innerWidth,window.innerHeight);场景旋转Y(10/60/60);renderer.render(场景,摄影机);})();window.addEventListener窗口('调整大小',函数(){renderer.setSize(window.innerWidth,window.innerHeight);camera.aspx ect=window.innerWidth/window.innerHeight;camera.updateProjectionMatrix();},假的);pen3D={drawTrunk:函数(根,大小){//root.skin=皮肤(0.5、0.3、0.2);root.add(新的三个网格(新的三维圆柱体几何体(大小/12,大小/10,大小16),root.skin).translateY(大小/2));root.add(新的THREE.Mesh(新的THEREE.SphereGeometry(size/12,16),root.skin).translateY(大小));返回根;},drawLeaf:功能(茎){stem.skin.color.setRGB(0,1,0);stem.add(新的三个网格(新的三维圆柱体几何体(0,0.02,0.6),茎.皮肤).旋转X(0.3).平移Y(0.3));stem.add(新的THREE.Mesh(新的THREE.CircleGeometry(0.2),茎.皮肤).旋转X(0.3).平移Y(0.4));返回阀杆;},事物:函数(){三.Object3D.调用(this);this.skin=新的THREE.MeshLambertMaterial({颜色:新三。颜色(0.5,0.3,0.2),vertexColors:THREE.FaceColors(顶点颜色),边:三边,双面})}};pen3D.Thing.prototype=对象创建(THREE.Object3D.prototype);pen3D.Thing.prototype.tilt=pen3D.Thing.prototype.rotateX;pen3D.Thing.prototype.turn=pen3D.Thing.prototype.rotateY;pen3D.Thing.prototype.move=pen3D.Thing.prototype.translateY;pen3D.center=新pen3D.Thing;scene.add(pen3D.center);返回pen3D;}<script src=“https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js“></script>

3D内容隐藏在setup3D()中,只是为了让它比console.log()少一些无聊。顺便说一下,角度是用弧度来测量的。

经测试可在Firefox和Chrome中运行。未在Internet Explorer和iOS(iPad)中实施。试着自己运行它。

在我再次找到答案后,加布里埃尔·拉特纳一年前对sleep()的JavaScript版本是什么做出了类似的回答?。

我在JavaScript sleep/wait上搜索了很多网页。。。如果你想让JavaScript“RUN,DELAY,RUN”。。。大多数人得到的要么是“RUN,RUN(无用的东西),RUN”,要么是“RUN,RUN+延迟RUN”。。。

我想:这是一个有效的解决方案。。。但你必须把你的跑步代码切碎…:是的,我知道,这只是一个更容易理解的重构。。。还

示例1:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
// JavaScript sleep by "therealdealsince1982"; copyrighted 2009
// setInterval
var i = 0;

function run() {
    // Pieces of codes to run
    if (i == 0){document.getElementById("id1").innerHTML= "<p>code segment " + i + " is ran</p>"; }
    if (i == 1){document.getElementById("id1").innerHTML= "<p>code segment " + i + " is ran</p>"; }
    if (i == 2){document.getElementById("id1").innerHTML= "<p>code segment " + i + " is ran</p>"; }
    if (i >2){document.getElementById("id1").innerHTML= "<p>code segment " + i + " is ran</p>"; }
    if (i == 5){document.getElementById("id1").innerHTML= "<p>all code segment finished running</p>"; clearInterval(t); } // End interval, stops run
    i++; // Segment of code finished running, next...
}

run();
t = setInterval("run()", 1000);

</script>
</body>
</html>

示例2:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
// JavaScript sleep by "therealdealsince1982"; copyrighted 2009
// setTimeout
var i = 0;

function run() {
    // Pieces of codes to run, can use switch statement
    if (i == 0){document.getElementById("id1").innerHTML= "<p>code segment " + i + " ran</p>"; sleep(1000);}
    if (i == 1){document.getElementById("id1").innerHTML= "<p>code segment " + i + " ran</p>"; sleep(2000);}
    if (i == 2){document.getElementById("id1").innerHTML= "<p>code segment " + i + " ran</p>"; sleep(3000);}
    if (i == 3){document.getElementById("id1").innerHTML= "<p>code segment " + i + " ran</p>";} //stops automatically
    i++;
}

function sleep(dur) {t=setTimeout("run()", dur);} // Starts flow control again after 'dur'

run(); // Starts
</script>
</body>
</html>

示例3:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
// JavaScript sleep by "therealdealsince1982"; copyrighted 2009
// setTimeout
var i = 0;

function flow() {
    run(i);
    i++; // Code segment finished running, increment i; can put elsewhere
    sleep(1000);
    if (i == 5) {clearTimeout(t);} // Stops flow, must be after sleep()
}

function run(segment) {
    // Pieces of codes to run, can use switch statement
    if (segment == 0){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    if (segment == 1){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    if (segment == 2){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    if (segment >2){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
}

function sleep(dur) {t=setTimeout("flow()", dur);} // Starts flow control again after 'dur'

flow(); // Starts flow
</script>
</body>
</html>

示例4:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
// JavaScript sleep by "therealdealsince1982"; copyrighted 2009
// setTimeout, switch
var i = 0;

function flow() {
    switch(i)
    {
        case 0:
            run(i);
            sleep(1000);
            break;
        case 1:
            run(i);
            sleep(2000);
            break;
        case 5:
            run(i);
            clearTimeout(t); // Stops flow
            break;
        default:
            run(i);
            sleep(3000);
            break;
    }
}

function run(segment) {
    // Pieces of codes to run, can use switch statement
    if (segment == 0){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    if (segment == 1){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    if (segment == 2){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    if (segment >2){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    i++; // Current segment of code finished running, next...
}

function sleep(dur) {t=setTimeout("flow()", dur);} // Starts flow control again after 'dur'

flow(); // Starts flow control for first time...
</script>
</body>
</html>

让事情看起来像大多数人想要的更好的解决方案是使用匿名函数:

alert('start');
var a = 'foo';
// Lots of code
setTimeout(function(){  // Beginning of code that should run AFTER the timeout
    alert(a);
    // Lots more code
}, 5000);  // Put the timeout here

这可能是最接近你想要的东西。

注意,如果你需要多次睡眠,这可能会在匆忙中变得很难看,你可能需要重新考虑你的设计。