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

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

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


当前回答

等待支持和蓝鸟承诺:

await bluebird.delay(1000);

这将像C语言的同步休眠(1)一样工作。我最喜欢的解决方案。

其他回答

如果确实要暂停脚本,可以执行以下操作:

var milliseconds;
var pretime;
var stage;

function step(time){
  switch(stage){
    case 0:
      //Code before the pause

      pretime=time;
      milliseconds=XXX;
      stage=1;
      break;
    case 1:
      //Code that is looped through while paused

      if(time-pretime >= milliseconds){
        //Code after the pause

        pretime=time;
        milliseconds=XXX;
        stage=2;
      }
      break;
    case 2:
      //Code that is looped through while paused

      if(time-pretime >= milliseconds){
        //Code after the pause

        pretime=time;
        milliseconds=XXX;
        stage=3;
      }
      break;
    case 3:
      //Etc...
  }

  Window.requestAnimationFrame(step)
}

step();

如果您使用循环,这可能正是您想要的,并且您可以以某种方式对其进行更改,从而获得伪多线程,其中一些函数等待一段时间,其他函数正常运行。我一直在纯JavaScript游戏中使用这个。

从该链接获取的代码不会冻结计算机。但它只在Firefox中有效。

/**
 * Netscape compatible WaitForDelay function.
 * You can use it as an alternative to Thread.Sleep() in any major programming language
 * that support it while JavaScript it self doesn't have any built-in function to do such a thing.
 * parameters:
 * (Number) delay in millisecond
 */
function nsWaitForDelay(delay) {
    /**
     * Just uncomment this code if you're building an extension for Firefox.
     * Since Firefox 3, we'll have to ask for user permission to execute XPCOM objects.
     */
    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");

    // Get the current thread.
    var thread = Components.classes["@mozilla.org/thread-manager;1"].getService(Components.interfaces.nsIThreadManager).currentThread;

    // Create an inner property to be used later as a notifier.
    this.delayed = true;

    /* Call JavaScript setTimeout function
      * to execute this.delayed = false
      * after it finishes.
      */
    setTimeout("this.delayed = false;", delay);

    /**
     * Keep looping until this.delayed = false
     */
    while (this.delayed) {
        /**
         * This code will not freeze your browser as it's documented in here:
         * https://developer.mozilla.org/en/Code_snippets/Threads#Waiting_for_a_background_task_to_complete
         */
        thread.processNextEvent(true);
    }
}

如果必须处理同步执行,我可以理解睡眠函数的用途。setInterval和setTimeout函数创建一个并行执行线程,该线程将执行序列返回到主程序,如果您必须等待给定的结果,这是无效的。当然,可以使用事件和处理程序,但在某些情况下,这不是预期的。

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版本是什么做出了类似的回答?。

这里有一个使用同步XMLHttpRequest的简单解决方案:

function sleep(n){
  var request = new XMLHttpRequest();
  request.open('GET', '/sleep.php?n=' + n, false);  // `false` makes the request synchronous
  request.send(null);
}

sleep.php文件的内容:

<?php sleep($_GET['n']);

现在用以下方式调用它:

sleep(5);

使用现有服务器实现

如果您没有自己的应用程序服务器(对于上面的PHP脚本),可以使用一些在线服务。例如:

函数睡眠(n){var request=new XMLHttpRequest();request.open('GET','http://httpstat.us/200?sleep='+n,假);request.send(空);};睡眠(1000);console.log(“一秒延迟完成”);

支持

关于为异步参数传递false,mdn注意到:

主线程上的同步请求很容易破坏用户体验,应该避免;事实上,许多浏览器已完全弃用主线程上的同步XHR支持。Workers中允许同步请求。

实际延迟时间

作为参数传递的毫秒数将是服务器在接收请求和发送响应之间等待的时间。传输和服务器负载所引起的延迟将被添加到其中。