什么是JavaScript版本的睡眠()?

有没有比以下pausecomp函数(从这里带走)更好的方法在JavaScript中设计sleep

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

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

4172006 次浏览

为了$DEITY的爱,请不要做一个忙碌等待的睡眠函数。setTimeoutsetInterval做你需要的一切。

var showHide = document.getElementById('showHide');setInterval(() => {showHide.style.visibility = "initial";setTimeout(() => {showHide.style.visibility = "hidden"}, 1000);}, 2000);   
<div id="showHide">Hello! Goodbye!</div>

Every two second interval hide text for one second. This shows how to use setInterval and setTimeout to show and hide text each second.

你不能在JavaScript中进行这样的睡眠,或者更确切地说,你不应该这样做。运行睡眠或这时循环将导致用户的浏览器挂起,直到循环完成。

使用您引用的链接中指定的计时器。

在JavaScript中,我重写了每个函数,以便它可以尽快结束。您希望浏览器重新控制,以便它可以更改您的DOM。

每次我想在函数中间睡觉时,我都会重构为使用setTimeout()

编辑

任何语言中臭名昭著的睡眠或延迟函数都备受争议。有些人会说,应该始终有一个信号或回调来触发给定的功能,其他人会争辩说,有时任意的延迟时刻是有用的。我说,在这个行业中,每个人都有自己的一条规则永远无法决定任何事情。

编写睡眠函数很简单,并且在JavaScript Promises中更有用:

// sleep time expects millisecondsfunction sleep (time) {return new Promise((resolve) => setTimeout(resolve, time));}
// Usage!sleep(500).then(() => {// Do something after the sleep!});

第一:

定义一个你想像这样执行的函数:

function alertWorld(){alert("Hello, World!");}

然后使用设置超时方法安排其执行:

setTimeout(alertWorld, 1000)

注意两件事

  • 第二个参数是以毫秒为单位的时间
  • 作为第一个参数,您必须仅传递函数的名称(引用),不带括号

我同意其他的海报。忙碌的睡眠只是一个坏主意。

但是,setTimeout不会阻止执行。它会在超时设置后立即执行函数的下一行,而不是在超时到期后执行,因此不会完成与睡眠相同的任务。

这样做的方法是将您的功能分解为之前和之后的部分。

function doStuff(){// Do some thingssetTimeout(continueExecution, 10000) // Wait ten seconds before continuing}
function continueExecution(){// Finish doing things after the pause}

确保您的函数名称仍然准确地描述了每个部分正在做什么(即GatherInput Then等待和CheckInput,而不是函数Part 1和函数Part 2)

此方法实现了在超时之后之前不执行您决定的代码行的目的,同时仍然将控制权返回给客户端PC以执行它排队的任何其他内容。

正如评论中指出的那样,这绝对是循环中的不工作。你可以做一些花哨的(丑陋的)黑客来使它在循环中工作,但一般来说,这只会产生灾难性的意大利面条代码。

如果您使用的是jQuery,实际上有人创建了一个“延迟”插件,它只不过是setTimeout的包装器:

// Delay Plugin for jQuery// - http://www.evanbot.com// - © 2008 Evan Byrne
jQuery.fn.delay = function(time,func){this.each(function(){setTimeout(func,time);});
return this;};

然后,您可以按预期在一排函数调用中使用它:

$('#warning').addClass('highlight').delay(1000).removeClass('highlight');

我搜索/谷歌了很多关于JavaScript睡眠/等待的网页……如果你想让JavaScript“运行,延迟,运行”,答案是0……大多数人得到的要么是“运行,运行(无用的东西),运行”,要么是“运行,运行+延迟运行”……

我想:这是一个有效的解决方案……但你必须砍掉你正在运行的代码……:是的,我知道,这只是一个更容易阅读的重构……仍然……

示例1:

<html><body><div id="id1">DISPLAY</div>
<script>// JavaScript sleep by "therealdealsince1982"; copyrighted 2009// setIntervalvar i = 0;
function run() {// Pieces of codes to runif (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 runi++; // 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// setTimeoutvar i = 0;
function run() {// Pieces of codes to run, can use switch statementif (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 automaticallyi++;}
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// setTimeoutvar i = 0;
function flow() {run(i);i++; // Code segment finished running, increment i; can put elsewheresleep(1000);if (i == 5) {clearTimeout(t);} // Stops flow, must be after sleep()}
function run(segment) {// Pieces of codes to run, can use switch statementif (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, switchvar 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 flowbreak;default:run(i);sleep(3000);break;}}
function run(segment) {// Pieces of codes to run, can use switch statementif (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>

对于想要为循环执行的一组调用留出空间的特定情况,您可以在原型中使用类似下面的代码。如果没有原型,您可以用setTimeout替换延迟函数。

function itemHandler(item){alert(item);}
var itemSet = ['a','b','c'];
// Each call to itemHandler will execute// 1 second apartfor(var i=0; i<itemSet.length; i++){var secondsUntilExecution = i;itemHandler.delay(secondsUntilExecution, item)}

在一种情况下,你可能想要一个睡眠()函数而不是使用setTimeout(),如果你有一个响应用户单击的函数,最终将打开一个新的弹出窗口,并且你已经启动了一些处理,这些处理需要在弹出窗口显示之前短时间完成。将打开的窗口移动到闭包中意味着它通常会被浏览器阻止。

(见2016年更新答案

我认为想要执行一个操作,等待,然后执行另一个操作是完全合理的。如果您习惯于使用多线程语言编写,您可能会想到在线程唤醒之前的一段时间内产生执行。

这里的问题是JavaScript是一个基于事件的单线程模型。虽然在特定情况下,让整个引擎等待几秒钟可能会很好,但一般来说这是不好的做法。假设我想在编写自己的函数时使用你的函数?当我调用你的方法时,我的方法都会冻结。如果JavaScript可以以某种方式保留你的函数的执行上下文,将其存储在某个地方,然后将其恢复并稍后继续,那么睡眠可能会发生,但这基本上就是线程。

因此,您几乎坚持其他人的建议-您需要将代码分解为多个函数。

那么,你的问题是一个错误的选择。没有办法以你想要的方式睡觉,你也不应该追求你建议的解决方案。

我也搜索了睡眠解决方案(不适用于生产代码,仅适用于开发和测试),发现了这篇文章:

JavaScript的睡眠()或等待()

…这是另一篇关于客户端解决方案的文章:JavaScript睡眠

此外,当您调用alert()时,您的代码也将暂停,同时显示警报-您需要找到一种不显示警报但获得相同效果的方法。:)

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

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

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

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

请注意,如果您需要多次睡眠,这可能会很快变得丑陋,您可能实际上需要重新考虑您的设计。

首先-setTimeout和setInterval是应该使用的,因为JavaScript的回调性质。如果你想使用sleep(),那就是控制流或代码架构不正确。

话虽如此,我想我仍然可以帮助实现两个睡眠。

1.假装同步运行我的头顶:

// A module to do that //dual-license: MIT or WTF [you can use it anyhow and leave my nickname in a comment if you want to]var _ = (function(){var queue = [];var play = function(){var go = queue.shift();if(go) {if(go.a) {go.f();play();}else{setTimeout(play, go.t);}}}return {go:function(f){queue.push({a:1, f:f});},sleep:function(t){queue.push({a:0, t:t});},playback:play}})();

[自动播放也应该是可能的]

// Usage
_.go(function(){
// Your codeconsole.log('first');
});
_.sleep(5000);
_.go(function(){
// Your codeconsole.log('next');
});
// This triggers the simulation_.playback();

2.真正同步运行

有一天我想了很多,我在JavaScript中真正睡眠的唯一想法是技术。

睡眠函数必须是同步 Ajax调用,超时设置为睡眠值。这就是拥有真正sleep()的唯一方法。

如果你想让一个匿名函数休眠,就像你创建的处理程序一样,我建议如下:

function(){if (!wait_condition){setTimeout(arguments.callee, 100, /* Comma-separated arguments here */);}// The rest of the function}

这段代码说:“如果等待条件尚未满足,请使用这些参数再次调用此函数。”我使用此方法将相同的参数传递给我的处理程序,有效地使此代码成为非轮询睡眠()(仅在函数开始时起作用)。

如果(像我一样)你正在使用犀牛的JavaScript,你可以使用…

try{java.lang.Thread.sleep(timeInMilliseconds);}catch (e){/** This will happen if the sleep is woken up - you might want to check* if enough time has passed and sleep again if not - depending on how* important the sleep time is to you.*/}

取自此链接的代码不会冻结计算机。但它仅适用于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);}}

需要使用“睡眠”方法的对象的方法,如下所示:

function SomeObject() {this.SomeProperty = "xxx";return this;}SomeObject.prototype.SomeMethod = function () {this.DoSomething1(arg1);sleep(500);this.DoSomething2(arg1);}

几乎可以翻译成:

function SomeObject() {this.SomeProperty = "xxx";return this;}SomeObject.prototype.SomeMethod = function (arg1) {var self = this;self.DoSomething1(arg1);setTimeout(function () {self.DoSomething2(arg1);}, 500);}

所不同的是,在执行“做某事2”之前,“某种方法”的操作返回。“某种方法”的调用者不能依赖于此。由于“睡眠”方法不存在,我使用后一种方法并相应地设计我的代码。

在某些情况下,一个很好的替代方案是显示一个顶级消息面板来停止用户交互,然后当你得到你正在等待的结果时(异步)再次隐藏它。这允许浏览器继续执行后台任务,但暂停工作流,直到你得到你的结果。

给你。正如代码所说,不要成为一个糟糕的开发人员并在网站上使用它。这是一个开发实用函数。

// Basic sleep function based on ms.// DO NOT USE ON PUBLIC FACING WEBSITES.function sleep(ms) {var unixtime_ms = new Date().getTime();while(new Date().getTime() < unixtime_ms + ms) {}}

为了测试的目的,我需要一个忙碌的等待。我不想拆分代码,因为这将是大量的工作,所以一个简单的进行为我做了这件事。

for (var i=0; i<1000000; i++){// Waiting}

我没有看到这样做的任何缺点,它对我起了作用。

可以使用Java的睡眠方法来完成。我已经在Firefox和Internet Explorer中测试过它,它不会锁定计算机,消耗资源或导致无休止的服务器点击。对我来说,这似乎是一个干净的解决方案。

首先,您必须在页面上加载Java并使其方法可用。为此,我这样做了:

<html><head>
<script type="text/javascript">
function load() {var appletRef = document.getElementById("app");window.java = appletRef.Packages.java;} // endfunction
</script>
<body onLoad="load()">
<embed id="app" code="java.applet.Applet" type="application/x-java-applet" MAYSCRIPT="true" width="0" height="0" />

然后,当您希望在JavaScript代码中无痛暂停时,您所要做的就是:

java.lang.Thread.sleep(xxx)

其中xxx是以毫秒为单位的时间。在我的案例中(作为理由),这是一家非常小的公司后端订单履行的一部分,我需要打印一张必须从服务器加载的发票。我通过将发票(作为网页)加载到iFrame中,然后打印iFrame来做到这一点。

当然,我必须等到页面完全加载后才能打印,所以JavaScript代码不得不暂停。我通过让发票页面(在iFrame中)使用onLoad事件更改父页面上的隐藏表单字段来实现这一点。父页面上打印发票的代码看起来像这样(为了清晰起见,切断了不相关的部分):

var isReady = eval('document.batchForm.ready');isReady.value = 0;
frames['rpc_frame'].location.href = url;
while (isReady.value == 0) {java.lang.Thread.sleep(250);} // endwhile
window.frames['rpc_frame'].focus();window.frames['rpc_frame'].print();

因此,用户按下按钮,脚本加载发票页面,等待,每季度检查一次发票页面是否已完成加载,然后弹出打印对话框供用户将其发送到打印机。QED。

或者创建这个:

function yourFunction(){
// Do somethingsetInterval(myFunc(), 1000);// Do something else}
function myFunc(){return;}

这将只等待指定的间隔并调用什么都不做的函数。

对于浏览器,我同意setTimeout和setInterval是要走的路。

但是对于服务器端代码,它可能需要阻塞功能(例如,因此您可以有效地进行线程同步)。

如果您使用的是Node.js流星,您可能遇到了在光纤中使用setTimeout的限制。这是服务器端睡眠的代码。

var Fiber = require('fibers');
function sleep(ms) {var fiber = Fiber.current;setTimeout(function() {fiber.run();}, ms);Fiber.yield();}
Fiber(function() {console.log('wait... ' + new Date);sleep(1000);console.log('ok... ' + new Date);}).run();console.log('back in main');

见:Node.js纤维,睡眠

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

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});});});

Firebug(可能还有其他JavaScript控制台)中,在按下回车键后没有发生任何事情,只有在指定的睡眠持续时间之后(…)

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

使用示例:

function sleepFor(sleepDuration){var now = new Date().getTime();while(new Date().getTime() < now + sleepDuration){/* Do nothing */}}
function sleepThenAct(){sleepFor(2000);console.log("Hello, JavaScript sleep!");}
sleepThenAct()

注:仅用于调试和开发

我使用多线程HTML5 Worker,它将能够中止指向无响应URL的同步XMLHttpRequest。这不会阻止浏览器。

简短的答案是,而不是JavaScript本身。您的解决方案似乎是不将控制权返回环境的唯一方法。

如果环境不支持事件,这是必要的。它们可能也不支持设置超时

如果您处于事件驱动的环境中,例如浏览器或Node.js,那么设置超时绝对是最好的方法。

function sleep(milliseconds) {var start = new Date().getTime();for (var i = 0; i < 1e7; i++) {if ((new Date().getTime() - start) > milliseconds){break;}}}

我确信有一百万种方法可以做得更好,但我想我应该通过创建一个对象来尝试一下:

// execute code consecutively with delays (blocking/non-blocking internally)function timed_functions(){this.myfuncs = [];this.myfuncs_delays = []; // mirrors keys of myfuncs -- values stored are custom delays, or -1 for use defaultthis.myfuncs_count = 0; // increment by 1 whenever we add a functionthis.myfuncs_prev    = -1; // previous index in arraythis.myfuncs_cur    = 0; // current index in arraythis.myfuncs_next  = 0; // next index in arraythis.delay_cur     = 0; // current delay in msthis.delay_default = 0; // default delay in msthis.loop = false;      // will this object continue to execute when at end of myfuncs array?this.finished = false;  // are we there yet?this.blocking = true;   // wait till code completes before firing timer?this.destroy = false;   // <advanced> destroy self when finished

this.next_cycle = function() {var that  = this;var mytimer = this.delay_default;
if(this.myfuncs_cur > -1)if(this.myfuncs_delays[this.myfuncs_cur] > -1)mytimer = this.myfuncs_delays[this.myfuncs_cur];
console.log("fnc:" + this.myfuncs_cur);console.log("timer:" + mytimer);console.log("custom delay:" + this.myfuncs_delays[this.myfuncs_cur]);setTimeout(function() {// Time is up! Next cycle...that.cycle();
}, mytimer);}
this.cycle = function() {
// Now check how far we are along our queue.. is this the last function?if(this.myfuncs_next + 1 > this.myfuncs_count){if(this.loop){console.log('looping..');this.myfuncs_next = 0;}elsethis.finished = true;}
// First check if object isn't finishedif(this.finished)return false;
// HANDLE NON BLOCKING //if(this.blocking != true) // Blocking disabled{console.log("NOT BLOCKING");this.next_cycle();}
// Set prev = current, and current to next, and next to new nextthis.myfuncs_prev = this.myfuncs_cur;this.myfuncs_cur  = this.myfuncs_next;this.myfuncs_next++;
// Execute current slotthis.myfuncs[this.myfuncs_cur]();
// HANDLE BLOCKINGif(this.blocking == true)  // Blocking enabled{console.log("BLOCKING");this.next_cycle();}
return true;};
// Addersthis.add = {that:this,
fnc: function(aFunction) {// Add to the function arrayvar cur_key = this.that.myfuncs_count++;this.that.myfuncs[cur_key] = aFunction;// Add to the delay reference arraythis.that.myfuncs_delays[cur_key] = -1;}}; // end::this.add
// settersthis.set = {that:this,
delay: function(ms) {var cur_key = this.that.myfuncs_count - 1;// This will handle the custom delay array this.that.myfunc_delays// Add a custom delay to your function container
console.log("setting custom delay. key: "+ cur_key + " msecs: " + ms);if(cur_key > -1){this.that.myfuncs_delays[cur_key] = ms;}// So now we create an entry on the delay variable},
delay_cur:      function(ms) { this.that.delay_cur = ms; },delay_default:  function(ms) { this.that.delay_default = ms; },loop_on:        function()   { this.that.loop = true; },loop_off:       function()   { this.that.loop = false; },blocking_on:    function()   { this.that.blocking = true; },blocking_off:   function()   { this.that.blocking = false; },
finished:            function(aBool) { this.that.finished = true; }}; // end::this.set

// Settersthis.get = {that:this,
delay_default: function() { return this.that.delay_default; },delay_cur:     function() { return this.that.delay_cur; }}; // end::this.get
} // end:::function timed_functions()

并像这样使用它:

// // // BEGIN :: TEST // // //
// Initializevar fncTimer = new timed_functions;
// Set some defaultsfncTimer.set.delay_default(1000);fncTimer.set.blocking_on();// fncTimer.set.loop_on();// fncTimer.set.loop_off();

// BEGIN :: ADD FUNCTIONS (they will fire off in order)fncTimer.add.fnc(function() {console.log('plan a (2 secs)');});fncTimer.set.delay(2000); // Set a custom delay for previously added function
fncTimer.add.fnc(function() {console.log('hello world (delay 3 seconds)');});fncTimer.set.delay(3000);
fncTimer.add.fnc(function() {console.log('wait 4 seconds...');});fncTimer.set.delay(4000);
fncTimer.add.fnc(function() {console.log('wait 2 seconds');});fncTimer.set.delay(2000);
fncTimer.add.fnc(function() {console.log('finished.');});// END :: ADD FUNCTIONS

// NOW RUNfncTimer.cycle(); // Begin execution

// // // END :: TEST // // //

您可以将闭包调用setTimeout()与增量较大的值一起使用。

var items = ['item1', 'item2', 'item3'];
function functionToExecute(item) {console.log('function executed for item: ' + item);}
$.each(items, function (index, item) {var timeoutValue = index * 2000;setTimeout(function() {console.log('waited ' + timeoutValue + ' milliseconds');functionToExecute(item);}, timeoutValue);});

结果:

waited 0 millisecondsfunction executed for item: item1waited 2000 millisecondsfunction executed for item: item2waited 4000 millisecondsfunction executed for item: item3

如果您喜欢建议不要失去性能。setTimeout是您期望的sleep。但是,如果你想要一个代码被sleep“中间分割”的语法,我们可以这样做:

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();

这里的大多数答案都是错误的,或者至少是过时的。JavaScript没有理由必须是单线程的,事实上也不是。今天所有的主流浏览器都支持工作线程。在此之前,其他JavaScript运行时,如犀牛和Node.js支持多线程。

“JavaScript是单线程的”不是一个有效的答案。例如,在工作线程中运行睡眠函数不会阻止UI线程中运行的任何代码。

在支持生成器和产量的较新的运行时中,可以在单线程环境中为睡眠函数带来类似的功能:

// This is based on the latest ES6 drafts.// JavaScript 1.7+ (SpiderMonkey/Firefox 2+) syntax is slightly different
// Run code you want to sleep here (omit star if using JavaScript 1.7)function* main(){for (var i = 0; i < 10; i++) {// To sleep for 10 milliseconds 10 times in a rowyield 10;}
yield 5;console.log('I just slept 5 milliseconds!');}
// Resume the given generator after ms millisecondsfunction resume(ms, generator){setTimeout(function(){// Omit .value if using JavaScript 1.7var nextSleep = generator.next().value;resume(nextSleep, generator);}, ms);}
// Initialize a generator and get first sleep for the recursive functionvargenerator = main(),firstSleep = generator.next().value;
// Initialize recursive resume functionresume(firstSleep, generator);

这种对睡眠的模仿不同于真正的睡眠函数,因为它不会阻塞线程。它只是JavaScript当前设置超时函数之上的糖。这种功能类型已在Task.js中实现,今天应该可以在Firefox中使用。

拥抱JavaScript的异步特性!

以下所有内容都将立即返回,但只有一个位置用于放置您想在发生某些事情后运行的代码。

我在这里概述的方法都适用于不同的用例,并且根据其复杂性大致排序。

不同的事情如下:

  • 等待某些条件成为现实
  • 在调用单个回调之前等待一组方法完成(以任何顺序)
  • 在调用回调之前以特定顺序运行一系列具有共享状态的异步方法

等等

等待查看某些条件是否为真在没有任何可访问的回调来告诉您何时完成执行的情况下很有用。

这是一个非常基本的实现,假设条件在某个时候会变成true。通过一些调整,它可以扩展为更有用(例如,通过设置调用限制)。(我昨天才写了这个!)

function waitFor(predicate, successCallback) {setTimeout(function () {var result = predicate();if (result !== undefined)successCallback(result);elsewaitFor(predicate, successCallback);}, 100);}

调用代码:

beforeEach(function (done) {selectListField('A field');
waitFor(function () {var availableOptions = stores.scrapeStore(optionStore);if (availableOptions.length !== 0)return availableOptions;}, done);});

在这里,我调用加载ExtJS'store'的东西,并等待商店包含一些东西,然后再继续(之前茉莉测试框架)。

等待几件事情完成

我还需要在加载不同的方法完成后运行一个回调。你可以这样做:

createWaitRunner = function (completionCallback) {var callback = completionCallback;var completionRecord = [];var elements = 0;
function maybeFinish() {var done = completionRecord.every(function (element) {return element === true});
if (done)callback();}
return {getNotifier: function (func) {func = func || function (){};
var index = elements++;completionRecord[index] = false;
return function () {func.applyTo(arguments);completionRecord[index] = true;maybeFinish();}}}};

调用代码:

var waiter = createWaitRunner(done);
filterList.bindStore = waiter.getNotifier();includeGrid.reconfigure = waiter.getNotifier(function (store) {includeStore = store;});
excludeGrid.reconfigure = waiter.getNotifier(function (store) {excludeStore = store;});

您可以等待通知,也可以包装使用传递给函数的值的其他函数。当调用所有方法时,将运行done

按顺序运行异步方法

当我有一系列异步方法要连续调用时(在测试中也是如此),我使用了一种不同的方法。这有点类似于你可以在异步库中得到的东西-系列做同样的事情,我首先对那个库进行了一些阅读,看看它是否符合我的要求。不过,我认为我的API在处理测试方面更好(而且实现起来很有趣!)。

// Provides a context for running asynchronous methods synchronously// The context just provides a way of sharing bits of state// Use 'run' to execute the methods.  These should be methods that take a callback and optionally the context as arguments// Note the callback is provided first, so you have the option of just partially applying your function to the arguments you want// instead of having to wrap even simple functions in another function
// When adding steps you can supply either just a function or a variable name and a function// If you supply a variable name then the output of the function (which should be passed into the callback) will be written to the contextcreateSynchronisedRunner = function (doneFunction) {var context = {};
var currentPosition = 0;var steps = [];
// This is the loop. It is triggered again when each method finishesvar runNext = function () {var step = steps[currentPosition];step.func.call(null,function (output) {step.outputHandler(output);currentPosition++;
if (currentPosition === steps.length)return;
runNext();}, context);};
var api = {};
api.addStep = function (firstArg, secondArg) {var assignOutput;var func;
// Overloadsif (secondArg === undefined) {assignOutput = function () {};func = firstArg;}else {var propertyName = firstArg;assignOutput = function (output) {context[propertyName] = output;};func = secondArg;}
steps.push({func: func,outputHandler: assignOutput});};
api.run = function (completedAllCallback) {completedAllCallback = completedAllCallback || function(){};
var lastStep = steps[steps.length - 1];var currentHandler = lastStep.outputHandler;lastStep.outputHandler = function (output) {currentHandler(output);completedAllCallback(context);doneFunction();};
runNext();};
// This is to support more flexible use where you use a done function in a different scope to initialisation// For example, the done of a test but create in a beforeEachapi.setDoneCallback = function (done) {doneFunction = done;};
return api;};

调用代码:

beforeAll(function (done) {var runner = createSynchronisedRunner(done);runner.addStep('attachmentInformation', testEventService.getAttachmentCalled.partiallyApplyTo('cat eating lots of memory.jpg'));runner.addStep('attachment', getAttachment.partiallyApplyTo("cat eating lots of memory.jpg"));runner.addStep('noAttachment', getAttachment.partiallyApplyTo("somethingElse.jpg"));runner.run(function (context) {attachment = context.attachment;noAttachment = context.noAttachment;});});

这里的部分申请基本上是道格拉斯·克罗克福德的Curry实现的重命名版本。我正在使用的很多东西都将回调作为最终参数,所以简单的调用可以这样完成,而不必用额外的函数包装所有内容。

下面是一个使用同步XMLHttpRequest的简单解决方案:

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

文件sleep.php的内容:

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

现在调用它:

sleep(5);

使用现有的服务器实现

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

function sleep(n) {var request = new XMLHttpRequest();request.open('GET', 'http://httpstat.us/200?sleep=' + n, false);request.send(null);};
sleep(1000);console.log("one second delay completed.");

支持

关于为asynchronous参数传递falsemdn注意到:

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

实际延迟

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

如果你想要比setTimeoutsetInterval更不笨重的函数,你可以把它们包装在函数中,只是颠倒参数的顺序,给它们起一个漂亮的名字:

function after(ms, fn){ setTimeout(fn, ms); }function every(ms, fn){ setInterval(fn, ms); }

脚本编写版本:

after = (ms, fn)-> setTimeout fn, msevery = (ms, fn)-> setInterval fn, ms

然后,您可以将它们很好地用于匿名函数:

after(1000, function(){console.log("it's been a second");after(1000, function(){console.log("it's been another second");});});

现在它很容易读作“在N毫秒之后,…”(或“每N毫秒,…”)

如果你真的需要睡眠()来测试一些东西。但要注意,它会在调试时大部分时间使浏览器崩溃——可能这就是你需要它的原因。在生产模式下,我将注释掉这个函数。

function pauseBrowser(millis) {var date = Date.now();var curDate = null;do {curDate = Date.now();} while (curDate-date < millis);}

不要在循环中使用new Date(),除非您想浪费内存、处理能力、电池以及可能的设备寿命。

我知道这个问题是关于睡眠的,显然答案是这是不可能的。我认为睡眠的一个常见需求是按顺序处理异步任务;我知道我必须确定地处理它。

在许多情况下,它可能能够使用Promise(Ajax请求常用)。它们让你以同步的方式做异步的事情。还有成功/失败的处理,它们可以被链接。

它们是ECMAScript 6的一部分,所以浏览器支持还不全,主要是Internet Explorer不支持它们。还有一个名为Q的库用于执行承诺。

参考文献:

如果你在Node.js上,你可以看看纤维——一个对节点的本机C扩展,一种多线程模拟。

它允许您以阻塞光纤执行的方式执行真正的sleep,但它在主线程和其他光纤中是非阻塞的。

以下是他们自述文件中的一个例子:

// sleep.js
var Fiber = require('fibers');
function sleep(ms) {var fiber = Fiber.current;setTimeout(function() {fiber.run();}, ms);Fiber.yield();}
Fiber(function() {console.log('wait... ' + new Date);sleep(1000);console.log('ok... ' + new Date);}).run();console.log('back in main');

-结果是:

$ node sleep.jswait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)back in mainok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)

这是一种在.hta脚本中休眠的方法,这样当脚本唤醒时,它会按顺序执行下一个命令,这是循环中所必需的。这是真正的休眠;它不会在休眠期间让处理器忙碌。例如,处理器能够在休眠期间下载和渲染页面。

就一次,在代码的开头,开始

var WSHShell = new ActiveXObject ("WScript.Shell");

对于例如1秒=1000毫秒的睡眠,执行以下语句

WSHShell.Run('Sleep.js 1000', 3, true);

在与脚本相同的目录中是文件Sleep.js,其中包含以下一行:

WScript.Sleep(WScript.Arguments (0));

(注意;0在括号中,而不是括号中。)后者是实际执行睡眠的行。前面片段中的参数true使调用同步。前面参数中的3似乎没有任何影响,但您需要一些参数,以便true是第三个参数。

微软说“WScript对象……在调用它的属性和方法之前永远不需要实例化,它总是可以从任何脚本文件中获得”,但事实并非如此。它在一个独立的.js文件中可用,如上所述,但显然不在.hta文件使用的.js文件中,所以这就是为什么它必须在一个单独的文件中,如上所述调用。

我会将setTimeOut封装在Promise中,以便与其他异步任务保持代码一致性:小提琴中的Demo

function sleep(ms){return(new Promise(function(resolve, reject) {setTimeout(function() { resolve(); }, ms);}));}

它是这样使用的:

sleep(2000).then(function() {// Do something});

如果您习惯使用Promises,则很容易记住语法。

总结一下(就像在之前的回答中所说的那样):

JavaScript中没有内置的睡眠函数。您应该使用设置超时setInterval来实现类似的效果。

如果你真的想,你可以使用进行循环模拟睡眠功能,就像最初问题中显示的那样,但这会让你的CPU疯狂工作。在Web Worker内部,另一种解决方案是将XMLHttpRequest同步到无响应的IP地址并设置适当的超时。这将避免CPU利用率问题。这是一个代码示例:

// Works only inside a web worker
function sleep(milliseconds) {var req = new XMLHttpRequest();req.open("GET", "http://192.0.2.0/", false);req.timeout = milliseconds;try {req.send();} catch (ex) {
}}
console.log('Sleeping for 1 second...');sleep(1000);console.log('Slept!');
console.log('Sleeping for 5 seconds...')sleep(5000);console.log('Slept!');

2009年的一个老问题。现在在2015年,一个新的解决方案可以通过ECMAScript 2015 AKA ES6中定义的生成器实现。它于2015年6月获得批准,但之前在Firefox和Chrome中实现。现在可以使睡眠函数非忙、非阻塞并嵌套在循环和子函数中,而不会冻结浏览器。只需要纯JavaScript-没有库或框架。

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

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

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

这一切都在示例drawTree()中得到了证明。它在旋转的3D场景上绘制了一棵带有叶子的树。一棵树被绘制为主干,顶部有3个不同方向的部分。然后,在短暂的睡眠后递归调用drawTree(),将每个部分绘制为另一棵较小的树。一棵非常小的树仅被绘制为一片叶子。

每片叶子在从runSleepyTask()开始的单独任务中都有自己的生命。它在growLeaf()中出生、生长、坐下、褪色、坠落和死亡。速度由sleep()控制。这表明多任务处理是多么容易。

function* sleep(milliseconds) {yield milliseconds};
function runSleepyTask(task) {(function wakeup() {var result = task.next();if (!result.done) setTimeout(wakeup, result.value);})()}//////////////// written by Ole Middelboe  /////////////////////////////
pen3D =setup3D();var taskObject = new drawTree(pen3D.center, 5);runSleepyTask(taskObject);
function* drawTree(root3D, size) {if (size < 2) runSleepyTask(new growLeaf(root3D))else {pen3D.drawTrunk(root3D, size);for (var p of [1, 3, 5]) {var part3D = new pen3D.Thing;root3D.add(part3D);part3D.move(size).turn(p).tilt(1-p/20);yield* sleep(50);yield* drawTree(part3D, (0.7+p/40)*size);}}}
function* growLeaf(stem3D) {var leaf3D = pen3D.drawLeaf(stem3D);for (var s=0;s++<15;) {yield* sleep(100); leaf3D.scale.multiplyScalar(1.1)}yield* sleep( 1000 + 9000*Math.random() );for (var c=0;c++<30;) {yield* sleep(200); leaf3D.skin.color.setRGB(c/30, 1-c/40, 0)}for (var m=0;m++<90;) {yield* sleep( 50); leaf3D.turn(0.4).tilt(0.3).move(2)}leaf3D.visible = false;}///////////////////////////////////////////////////////////////////////
function setup3D() {var scene, camera, renderer, diretionalLight, pen3D;
scene = new THREE.Scene();camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight, 0.1, 1000);camera.position.set(0, 15, 20);renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });renderer.setSize(window.innerWidth, window.innerHeight);document.body.appendChild(renderer.domElement);
directionalLight = new THREE.DirectionalLight(0xffffaa, 0.7);directionalLight.position.set(-1, 2, 1);scene.add(directionalLight);scene.add(new THREE.AmbientLight(0x9999ff));
(function render() {requestAnimationFrame(render);// renderer.setSize( window.innerWidth, window.innerHeight );scene.rotateY(10/60/60);renderer.render(scene, camera);})();
window.addEventListener('resize',function(){renderer.setSize( window.innerWidth, window.innerHeight );camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();},false);
pen3D = {drawTrunk: function(root, size) {// root.skin = skin(0.5, 0.3, 0.2);root.add(new THREE.Mesh(new THREE.CylinderGeometry(size/12, size/10, size, 16),root.skin).translateY(size/2));root.add(new THREE.Mesh(new THREE.SphereGeometry(size/12, 16),root.skin).translateY(size));return root;},
drawLeaf: function(stem) {stem.skin.color.setRGB(0, 1, 0);stem.add(new THREE.Mesh(new THREE.CylinderGeometry(0, 0.02, 0.6),stem.skin) .rotateX(0.3).translateY(0.3));stem.add(new THREE.Mesh(new THREE.CircleGeometry(0.2),stem.skin) .rotateX(0.3).translateY(0.4));return stem;},
Thing: function() {THREE.Object3D.call(this);this.skin = new THREE.MeshLambertMaterial({color: new THREE.Color(0.5, 0.3, 0.2),vertexColors: THREE.FaceColors,side: THREE.DoubleSide})}};
pen3D.Thing.prototype = Object.create(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 = new pen3D.Thing;scene.add(pen3D.center);
return pen3D;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js"></script>

The 3D stuff is hidden inside setup3D() and is only included to make it less boring than console.log(). Angles are measured in radians by the way.

Tested to work in Firefox and Chrome. Not implemented in Internet Explore and iOS (iPads). Try to run it yourself.

After another pass of the answers I found, that Gabriel Ratener made a similar answer a year ago to What is the JavaScript version of sleep()?.

有一个新的库Sequencr.js,它将函数与超时整齐地链接在一起,这样您就可以避免回调地狱。

它变成了:

setTimeout(function(timeout){function1();setTimeout(function(timeout){function2();setTimeout(function(timeout){function3();}, timeout, timeout)}, timeout, timeout)}, 10, 10);

到这个:

Sequencr.chain([function1, function2, function3], 10);

并且内置支持在每次迭代之间“休眠”的循环。

另一种可能的方法是:

var _timer;clearTimeout(_timer);_timer = setTimeout(function() {// Your code}, 1000); // Delay for 1 s.

我浏览了一天的解决方案,但我仍然在考虑如何在使用回调时保持链接性。

每个人都熟悉传统的编程风格,即以同步的方式逐行运行代码。SetTimeout使用回调,因此下一行不会等待它完成。这让我思考如何使其“同步”,从而制作“睡眠”功能。

从一个简单的协程开始:

function coroutine() {console.log('coroutine-1:start');sleepFor(3000); // Sleep for 3 seconds hereconsole.log('coroutine-2:complete');}

我想在中间休眠3秒,但我不想主导整个流程,所以协程必须由另一个线程执行。我考虑统一产出指令,并修改协程如下:

function coroutine1() {this.a = 100;console.log('coroutine1-1:start');return sleepFor(3000).yield; // Sleep for 3 seconds hereconsole.log('coroutine1-2:complete');this.a++;}
var c1 = new coroutine1();

声明睡眠对于原型:

sleepFor = function(ms) {var caller = arguments.callee.caller.toString();var funcArgs = /\(([\s\S]*?)\)/gi.exec(caller)[1];var args = arguments.callee.caller.arguments;var funcBody = caller.replace(/^[\s\S]*?sleepFor[\s\S]*?yield;|}[\s;]*$/g,'');var context = this;setTimeout(function() {new Function(funcArgs, funcBody).apply(context, args);}, ms);return this;}

运行coroutine1后(我在Internet Explorer 11和Chrome49中测试过),您将看到它在两个控制台语句之间休眠3秒。

棘手的一点是在睡眠中例程。它将调用者函数体读取为字符串并将其分成两部分。删除上部并由下部创建另一个函数。等待指定的毫秒数后,它通过应用原始上下文和参数调用创建的函数。对于原始流,它将像往常一样以“返回”结束。对于“产量”?它用于正则表达式匹配。这是必要的,但根本没有用。

它并不是100%完美,但它至少完成了我的工作。我必须提到使用这段代码的一些限制。由于代码被分成两部分,“返回”语句必须在外部,而不是在任何循环或{}中。即

function coroutine3() {this.a = 100;console.log('coroutine3-1:start');if(true) {return sleepFor(3000).yield;} // <- Raise an exception hereconsole.log('coroutine3-2:complete');this.a++;}

上面的代码一定有问题,因为在创建的函数中不能单独存在右括号。另一个限制是“var xxx=123”声明的所有局部变量都不能携带到下一个函数。你必须使用“this.xxx=123”来实现同样的事情。如果你的函数有参数并且它们发生了变化,修改后的值也不能携带到下一个函数。

function coroutine4(x) { // Assume x=abcvar z = x;x = 'def';console.log('coroutine4-1:start' + z + x); // z=abc, x=defreturn sleepFor(3000).yield;console.log('coroutine4-2:' + z + x); // z=undefined, x=abc}

我将引入另一个函数原型:waitFor

waitFor = function(check, ms) {var caller = arguments.callee.caller.toString();var funcArgs = /\(([\s\S]*?)\)/gi.exec(caller)[1];var args = arguments.callee.caller.arguments;var funcBody = caller.replace(/^[\s\S]*?waitFor[\s\S]*?yield;|}[\s;]*$/g,'');var context = this;var thread = setInterval(function() {if(check()) {clearInterval(thread);new Function(funcArgs, funcBody).apply(context, args);}}, ms?ms:100);return this;}

它等待“check”函数,直到它返回true。它每100毫秒检查一次值。你可以通过传递额外的参数来调整它。考虑测试coroutine2:

function coroutine2(c) {/* Some code here */this.a = 1;console.log('coroutine2-1:' + this.a++);return sleepFor(500).yield;
/* Next */console.log('coroutine2-2:' + this.a++);console.log('coroutine2-2:waitFor c.a>100:' + c.a);return waitFor(function() {return c.a>100;}).yield;
/* The rest of the code */console.log('coroutine2-3:' + this.a++);}

也是我们到目前为止喜欢的漂亮风格。实际上我讨厌嵌套回调。很容易理解coroutine2将等待coroutine1的完成。有趣吗?好吧,然后运行以下代码:

this.a = 10;console.log('outer-1:' + this.a++);var c1 = new coroutine1();var c2 = new coroutine2(c1);console.log('outer-2:' + this.a++);

输出是:

outer-1:10coroutine1-1:startcoroutine2-1:1outer-2:11coroutine2-2:2coroutine2-2:waitFor c.a>100:100coroutine1-2:completecoroutine2-3:3

初始化coroutine1和coroutine2后立即完成外部。然后,coroutine1将等待3000毫秒。Coroutine2将在等待500毫秒后进入步骤2。之后,一旦检测到coroutine1. a值>100,它将继续步骤3。

注意有三个上下文来保存变量“a”。一个是外部,其值为10和11。另一个在coroutine1中,其值为100和101。最后一个在coroutine2中,其值为1,2和3。在coroutine2中,它还等待来自coroutine1的c. a,直到它的值大于100。3个上下文是独立的。

复制和粘贴的整个代码:

sleepFor = function(ms) {var caller = arguments.callee.caller.toString();var funcArgs = /\(([\s\S]*?)\)/gi.exec(caller)[1];var args = arguments.callee.caller.arguments;var funcBody = caller.replace(/^[\s\S]*?sleepFor[\s\S]*?yield;|}[\s;]*$/g,'');var context = this;setTimeout(function() {new Function(funcArgs, funcBody).apply(context, args);}, ms);return this;}
waitFor = function(check, ms) {var caller = arguments.callee.caller.toString();var funcArgs = /\(([\s\S]*?)\)/gi.exec(caller)[1];var args = arguments.callee.caller.arguments;var funcBody = caller.replace(/^[\s\S]*?waitFor[\s\S]*?yield;|}[\s;]*$/g,'');var context = this;var thread = setInterval(function() {if(check()) {clearInterval(thread);new Function(funcArgs, funcBody).apply(context, args);}}, ms?ms:100);return this;}
function coroutine1() {this.a = 100;console.log('coroutine1-1:start');return sleepFor(3000).yield;console.log('coroutine1-2:complete');this.a++;}
function coroutine2(c) {/* Some code here */this.a = 1;console.log('coroutine2-1:' + this.a++);return sleepFor(500).yield;
/* next */console.log('coroutine2-2:' + this.a++);console.log('coroutine2-2:waitFor c.a>100:' + c.a);return waitFor(function() {return c.a>100;}).yield;
/* The rest of the code */console.log('coroutine2-3:' + this.a++);}
this.a = 10;console.log('outer-1:' + this.a++);var c1 = new coroutine1();var c2 = new coroutine2(c1);console.log('outer-2:' + this.a++);

它在Internet Explorer 11和Chrome49中进行了测试。因为它使用arguments.callee,所以如果它在严格模式下运行可能会出现问题。

如果你真的想暂停一个脚本,你可以这样做:

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游戏中使用它。

LiveScript(编译为JavaScript)中,您可以执行以下操作:

sleep = (ms, func) -> set-timeout func, ms
console.log "hello-1"<- sleep 2000msconsole.log "hello-2"<- sleep 2000msconsole.log "hello-3"

这可能有用。它在C和JavaScript中对我有用。

function sleep(time) {var x = 0;for(x = 0;x < time;x++) {/* Do nothing */}}

使用三个功能:

  1. 调用setInterval开始循环的函数
  2. 一个函数,它调用clearInterval来停止循环,然后调用setTimeout来睡眠,最后调用setTimeout中的回调来重新启动循环
  3. 一个循环,它跟踪迭代次数,设置睡眠次数和最大次数,一旦达到睡眠次数就调用睡眠函数,并在达到最大次数后调用clearInterval

var foo = {};
function main(){'use strict';
/* Initialize global state */foo.bar = foo.bar || 0;
/* Initialize timer */foo.bop = setInterval(foo.baz, 1000);}
sleep =function(timer){'use strict';clearInterval(timer);timer = setTimeout(function(){main()}, 5000);};
foo.baz =function(){'use strict';
/* Update state */foo.bar = Number(foo.bar + 1) || 0;
/* Log state */console.log(foo.bar);
/* Check state and stop at 10 */(foo.bar === 5) && sleep(foo.bop);(foo.bar === 10) && clearInterval(foo.bop);};
main();

事件循环

参考文献

await支持和蓝鸟承诺

await bluebird.delay(1000);

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

2017-2021更新

自2009年提出这个问题以来,JavaScript已经有了显着的发展。所有其他答案现在都过时或过于复杂。这是当前的最佳实践:

function sleep(ms) {return new Promise(resolve => setTimeout(resolve, ms));}

或者作为一个单行:

await new Promise(r => setTimeout(r, 2000));

作为函数:

const sleep = ms => new Promise(r => setTimeout(r, ms));

在TypeScript中:

const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

使用它作为:

await sleep(<duration>);

演示:

function sleep(ms) {return new Promise(resolve => setTimeout(resolve, ms));}
async function demo() {for (let i = 0; i < 5; i++) {console.log(`Waiting ${i} seconds...`);await sleep(i * 1000);}console.log('Done');}
demo();

注意,

  1. await只能在以async关键字为前缀的函数中执行,或者在越来越多的环境中的脚本的顶层执行。
  2. await只暂停当前的async函数。这意味着它不会阻止脚本其余部分的执行,这是您在绝大多数情况下想要的。如果您确实想要一个阻塞构造,请参阅#26406126">这个答案使用#2.wait,但请注意,大多数浏览器不会在浏览器的主线程上允许它。

两个新的JavaScript特性(截至2017年)帮助编写了这个“睡眠”函数:

兼容性

如果由于某种原因您使用的是7岁以上的Node(达到了2017年生命终结),或者针对的是旧浏览器,async/await仍然可以通过巴别塔(一个将转译 JavaScript+新功能转换为普通旧JavaScript的工具)使用,使用#2插件。

这里大多数解决方案的问题是它们倒带堆栈。在某些情况下,这可能是一个大问题。在这个例子中,我展示了如何以不同的方式使用迭代器来模拟<强>真正的睡眠

在这个例子中,生成器正在调用它自己的next(),所以一旦它开始运行,它就会自己运行。

var h = a();h.next().value.r = h; // That's how you run it. It is the best I came up with
// Sleep without breaking the stack!!!function *a(){var obj = {};
console.log("going to sleep....2s")
setTimeout(function(){obj.r.next();}, 2000)yield obj;
console.log("woke up");console.log("going to sleep no 2....2s")setTimeout(function(){obj.r.next();}, 2000)yield obj;
console.log("woke up");console.log("going to sleep no 3....2s")
setTimeout(function(){obj.r.next();}, 2000)yield obj;
console.log("done");}

在服务器端,您可以使用deasyncsleep()方法,该方法在C中本机实现,因此它可以有效地实现等待效果,而不会阻塞事件循环或将CPU置于100%的负载。

示例:

#!/usr/bin/env node
// Requires `npm install --save deasync`var sleep = require("deasync").sleep;
sleep(5000);
console.log ("Hello World!!");

但是,如果您需要 JavaScript函数(例如,通过浏览器在客户端运行它),我很抱歉地说,我认为您的pausecomp()函数是处理它的唯一方法,而且更重要的是:

  1. 这不仅会暂停您的函数,还会暂停整个事件循环。因此不会参与其他事件。

  2. 它使您的CPU处于100%负载。

因此,如果您需要它来编写浏览器脚本并且不想要那些可怕的效果,我必须说您应该以某种方式重新考虑您的函数:

a)。您可以在超时时调用它(或调用do_the_rest()函数)。如果您不期望函数产生任何结果,这是更简单的方法。

b)。或者,如果您需要等待结果,那么您应该使用Promise(或者回调地狱,当然;-))。

无预期结果示例:

function myFunc() {
console.log ("Do some things");
setTimeout(function doTheRest(){console.log ("Do more things...");}, 5000);
// Returns undefined.};
myFunc();

一个返回Promise的例子(注意它改变了你的函数用法):

function myFunc(someString) {
return new Promise(function(resolve, reject) {
var result = [someString];result.push("Do some things");
setTimeout(function(){result.push("Do more things...");resolve(result.join("\n"));}, 5000);});};

// But notice that this approach affect to the function usage...// (It returns a promise, not actual data):myFunc("Hello!!").then(function(data){console.log(data);}).catch(function(err){console.error(err);});

我个人喜欢简单的:

function sleep(ms) {return new Promise((resolve) => setTimeout(resolve, ms));}

然后:

await sleep(2000); // Sleeps for 2 seconds

我一直在使用它来创建虚假的加载时间,同时在p5.js中创建脚本。

这会给你带来好处。

var reloadAfter = 10; //secondsvar intervalId = setTimeout(function() {//code you want to execute after the time waiting}, reloadAfter * 1000); // 60000 = 60 sec = 1 min

这个问题我已经问了很长时间了,我需要的答案并不完全是这里提供的。这个等待函数会导致同步等待,不会占用CPU。

函数等待向任何地方发出Ajax请求并将async标志设置为false。函数waitF对帧执行相同的操作,函数等等对div执行相同的操作。Ajax大约需要100毫秒,帧大约是25,div大约是1。

等待函数利用所有这些取决于你给它多少时间。如果它等待的时间不够长,那么再做一次。

我在处理多个异步加载元素时需要这个。基本上是“等待此元素存在”。您可以在https://jsfiddle.net/h2vm29ue/处使用它。它只是利用浏览器自然等待的东西。较长的版本https://jsfiddle.net/5cov1p0z/32/更精确。

 function waitForIt() {var start = new Date();var xhttp = new XMLHttpRequest();xhttp.onreadystatechange = function() {if (this.readyState == 4 && this.status == 200) {// Doesn't matter}};xhttp.open("GET", "WaitForIt", false);xhttp.send();var end = new Date();}//
function waitF() {var start = new Date();var ifram = document.createElement('iframe');ifram.id = 'ifram';ifram.src = '';var div = document.createElement('div');div.id = 'timer';document.body.appendChild(div);document.getElementById('timer').appendChild(ifram);document.getElementById('timer').removeChild(ifram);document.body.removeChild(div);var end = new Date();return (end - start);}

function waitD() {var start = new Date();var div = document.createElement('div');div.id = 'timer';document.body.appendChild(div);div.click();document.body.removeChild(div);var end = new Date();return (end - start);}
function wait(time) {var start = new Date();var end = new Date();while ((end - start < time)) {
if ((time - (end - start)) >= 200) {waitForIt();} else {if ((time - (end - start)) >= 50) {waitF();} else {waitD();}}end = new Date();}return (end - start);}

一个要休眠的函数,使用同步调用让操作系统执行它。使用您喜欢的任何操作系统睡眠命令。在使用CPU时间的意义上,它并不忙于等待。

我在一个不存在的地址上选择了ping。

const cp = require('child_process');
function sleep(ms){try{cp.execSync('ping 192.0.2.0 -n 1 -w '+ms);}catch(err){}}

一个测试来验证它的工作原理

console.log(Date.now());console.log(Date.now());sleep(10000);console.log(Date.now());console.log(Date.now());

一些测试结果。

14915752751361491575275157

(10秒后)

14915752850751491575285076

到目前为止,我读过的每一个解决方案都会像“让我们睡觉,看看明天发生了什么”。

setInterval(回调,时间)会等待很长时间,然后调用回调,阻塞运行时。“setInterval”的当前实现远非线程保存,甚至不介意并发。

虽然提到的稀疏解决方案看起来像C#(),但它们仍然不像在C#/. NET中那样工作。他们仍然像在C中一样工作。

JavaScript目前没有提供了一种实现真正多线程的架构。最好的方法是TypeScript,但仍然缺乏真正的解决方案,以至于……伤害。JavaScript、jQuery、AJAX、jNode,甚至TypeScript都只是一堆崇拜者,依赖于实现者情绪的好坏。事实。句号。

JavaScript功能不允许任何暂停。使用同步JavaScript,实现过程。过程等待I/O操作和睡眠超时。它可用于JavaScript 1.7。

演示:

要保持主线程忙碌几毫秒:

function wait(ms) {const start = performance.now();while(performance.now() - start < ms);}

现在也可以使用本机模块util来promisify常规同步函数。

const { promisify } = require('util')const sleep = promisify(setTimeout)
module.exports = () => {await someAsyncFunction()await sleep(2000)console.log('2 seconds later...')}

由于7.6,您可以将实用工具模块中的promisify函数与setTimeout组合。

const sleep = require('util').promisify(setTimeout)

一般用法

async function main() {console.time("Slept for")await sleep(3000)console.timeEnd("Slept for")}
main()

问题使用

async function asyncGenerator() {while (goOn) {var fileList = await listFiles(nextPageToken);await sleep(3000)var parents = await requestParents(fileList);}}

我有一个类似的问题,必须等待控制存在和检查间隔。由于JavaScript中没有真正的睡眠,等待或暂停,并且Internet Explorer不支持使用wait/async,因此我使用setTimeOut制作了一个解决方案,并在成功找到元素的情况下注入函数。这是完整的示例代码,因此每个人都可以复制并将其用于自己的项目:

<html><head><script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><script type="text/javascript">var ElementSearchStatus = {None: 0,Found: 1,NotFound: 2,Timeout: 3};
var maxTimeout = 5;var timeoutMiliseconds = 1000;
function waitForElement(elementId, count, timeout, onSuccessFunction) {++count;var elementSearchStatus = existsElement(elementId, count, timeout);if (elementSearchStatus == ElementSearchStatus.None) {window.setTimeout(waitForElement, timeoutMiliseconds, elementId, count, timeout, onSuccessFunction);}else {if (elementSearchStatus == ElementSearchStatus.Found) {onSuccessFunction();}}}
function existsElement(elementId, count, timeout) {var foundElements = $("#" + elementId);if (foundElements.length > 0 || count > timeout) {if (foundElements.length > 0) {console.log(elementId + " found");return ElementSearchStatus.Found;}else {console.log("Search for " + elementId + " timed out after " + count + " tries.");return ElementSearchStatus.Timeout;}}else {console.log("waiting for " + elementId + " after " + count + " of " + timeout);return ElementSearchStatus.None;}}
function main() {waitForElement("StartButton", 0, maxTimeout, function () {console.log("found StartButton!");DoOtherStuff("StartButton2")});}
function DoOtherStuff(elementId) {waitForElement(elementId, 0, maxTimeout, function () {console.log("found " + elementId);DoOtherStuff("StartButton3");});}</script></head><body><button type="button" id="StartButton" onclick="main();">Start Test</button><button type="button" id="StartButton2" onclick="alert('Hey ya Start Button 2');">Show alert</button></body></html>

一个非常简单的方法来做睡眠,与任何运行JavaScript的东西兼容……这段代码已经过大约500个条目的测试,CPU和内存使用在我的网络浏览器上仍然不可见。

这是一个等待直到节点变得可见的函数…

此函数创建一个新的上下文function () {}以避免递归。我们将与调用者代码相同的代码放置在这个新上下文中。我们使用函数Timeout在几秒钟后调用我们的函数。

var get_hyper = function(node, maxcount, only_relation) {if (node.offsetParent === null) {// node is hiddensetTimeout(function () { get_hyper(node, maxcount, only_relation)},1000);return;};
// Enter the code here that waits for that node becoming visible// before getting executed.
};

我更喜欢这个功能风格一个班轮sleep函数:

const sleep = (ms) => new Promise((res) => setTimeout(res, ms, ms));
// usageasync function main() {console.log("before");const t = await sleep(10_000); /* 10 sec */console.log("after " + t);}main();

我得到的Promise不是使用顶部答案的构造函数。如果你导入蓝鸟,你可以做到这一点。在我看来,这是最简单的解决方案。

import * as Promise from 'bluebird';
await Promise.delay(5000)

使用实际的睡眠函数的问题在于JavaScript是单线程的,而睡眠函数几乎会让您的浏览器选项卡在这段时间内挂起。

2019更新使用Atomics.wait

它应该在Node.js 9.3或更高版本中工作。

我需要一个非常准确的计时器在Node.js,它工作得很好。

但是,似乎浏览器中的支持非常有限。

let ms = 10000;Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);

运行了几个10秒的计时器基准测试。

使用setTimeout,我得到的错误高达7000微秒(7毫秒)。

使用原子,我的错误似乎保持在600微秒(0.6毫秒)以下

2020年更新:总结

function sleep(millis){ // Need help of a server-side pagelet netMillis = Math.max(millis-5, 0); // Assuming 5 ms overheadlet xhr = new XMLHttpRequest();xhr.open('GET', '/sleep.jsp?millis=' + netMillis + '&rand=' + Math.random(), false);try{xhr.send();}catch(e){}}
function sleepAsync(millis){ // Use only in async functionlet netMillis = Math.max(millis-1, 0); // Assuming 1 ms overheadreturn new Promise((resolve) => {setTimeout(resolve, netMillis);});}function sleepSync(millis){ // Use only in worker thread, currently Chrome-onlyAtomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, millis);}
function sleepTest(){console.time('sleep');sleep(1000);console.timeEnd('sleep');}
async function sleepAsyncTest(){console.time('sleepAsync');await sleepAsync(1000);console.timeEnd('sleepAsync');}
function sleepSyncTest(){let source = `${sleepSync.toString()}console.time('sleepSync');sleepSync(1000);console.timeEnd('sleepSync');`;let src = 'data:text/javascript,' + encodeURIComponent(source);console.log(src);var worker = new Worker(src);}

其中服务器端页面,例如sleep.jsp,看起来像:

<%try{Thread.sleep(Long.parseLong(request.getParameter("millis")));}catch(InterruptedException e){}%>

用途:

  await new Promise(resolve => setTimeout(resolve, 2000));

Make sure your calling function is async. This is verified and is working fine.

没有任何依赖的最短解决方案:

await new Promise(resolve => setTimeout(resolve, 5000));

如果你真的想完全阻止主线程并防止事件循环从事件队列中提取,这里有一个很好的方法来做到这一点,而无需创建任何函数、新的Date对象或泄露任何变量。我知道这个愚蠢的问题已经有一百万个答案了,但我没有看到有人使用这个确切的解决方案。这只适用于现代浏览器。

警告:这不是你会投入生产的东西。它只是有助于理解浏览器事件循环。它甚至可能对任何测试都没有用。它不像普通的系统睡眠函数,因为JavaScript运行时仍然在每个周期中工作。

for (let e = performance.now() + 2000; performance.now() < e; ) {}

在这里使用,setTimeout回调至少在两秒钟后才会被调用,即使它几乎立即进入事件队列:

setTimeout(function() {console.log("timeout finished");}, 0);
for (let e = performance.now() + 2000; performance.now() < e; ) {}console.log("haha wait for me first");

你会经历大约两秒的停顿,然后看到:

haha wait for me firsttimeout finished

使用performance.now()而不是Date.now()的好处是Date对象

受到时钟偏差和系统时钟调整的影响。该时间的价值可能并不总是单调增加随后的值可能会减少或保持不变。*

一般来说,performance.now()更适合以高精度测量时间差异。

使用for循环的好处是允许您在运行前将变量设置为块的本地变量。这允许您在循环之外进行加法运算,同时仍然是“单行”。这有望最大限度地减少此热循环刻录的CPU负载。

使用TypeScript:

这是一个可以等待的快速sleep()实现。这与顶部答案尽可能相似。它在功能上是等效的,除了ms在TypeScript中输入为number

const sleep = (ms: number) =>new Promise((resolve) => setTimeout(resolve, ms));
async function demo() {console.log('Taking a break for 2s (2000ms)...');await sleep(2000);console.log('Two seconds later');}
demo();

就是它了await sleep(<duration>)

注意,

  1. await只能在以async关键字为前缀的函数中执行,或者在某些环境中(例如,ChromeDevTools控制台或Runkit)在脚本的顶级处执行。
  2. await仅暂停当前async函数。

你可以这样做。所有函数都可以继承的睡眠方法:

Function.prototype.sleep = function(delay, ...args) {setTimeout(() => this(...args), delay)}
console.log.sleep(2000, 'Hello, World!!')

在睡眠方法中,您可以返回任何可执行的对象。不一定是新的承诺。

示例:

const sleep = (t) =>  ({ then: (r) => setTimeout(r, t) })
const someMethod = async () => {
console.log("hi");await sleep(5000)console.log("bye");}
someMethod()

我认为这个问题很好,指出了重要的观点和考虑因素。

话虽如此,我认为问题的核心在于意图和理解开发人员(您)想要控制的内容。

首先,名称sleep是一个重载的命名选择。即,“什么”将被“睡眠”;作为开发人员,我控制着“什么”?

在任何语言引擎中,在任何操作系统进程上运行,在任何裸机或托管系统上,“开发人员”都无法控制操作系统共享资源CPU内核[和/或线程]的(所有者),除非他们正在编写操作系统/进程系统本身。

作为应用程序/服务开发人员,最好考虑我控制着由os进程/语言引擎管理的工作流-活动-流。在某些系统上,这意味着我控制着一个原生os线程(可能共享CPU内核),在其他系统上,这意味着我控制着一个异步延续工作流链/树

在JavaScript的情况下,它是“后者”。

因此,当需要“睡眠”时,我打算使我的工作流程从执行中“延迟”一段时间,然后再执行工作流程中的下一个“步骤”(阶段/活动/任务)。

这是“恰当地”说,作为开发人员,最容易将(从某种意义上思考)模型作为线性代码流工作;根据需要诉诸工作流的组合来扩展。

今天,在JavaScript中,我们可以选择使用高效的多任务处理1980年代基于参与者的延续架构(重新标记为现代期货/承诺/然后/等待等)来设计这种线性工作流程。

考虑到这一点,我的答案是没有贡献了新的的技术解决方案,而是专注于问题本身的意图设计视角

我建议任何答案都从思考上述概念开始,然后选择一个名称(除了sleep)来提醒和暗示意图是什么。

工作流程

  • 选择1:delayWorkForMs(nMsToDelay)
  • 选择2:delayAsyncSequenceForMs(msPeriod)
async delayAsyncSequenceForMs(msPeriod) {await new Promise(resolve => setTimeout(resolve, msPeriod));}

请记住,任何async函数总是都返回Promise,而await只能在async函数中使用。
(哈哈,你可能会问自己为什么…)

  • 考虑1:不要使用“循环”来烧毁cpu周期。
  • 考虑2:在JavaScript模型中,当在非异步函数中时,您不能“延迟”(等待)“异步”工作流的执行(除非你在做坏事,不必要地燃烧cpu周期)。您只能“延迟”“异步”函数中的代码步骤。
    在内部,“async”函数被建模为每个await关键词处的入口点/延续的集合。如果您熟悉反引号插值模型,您可以“认为wait”在概念上与编写反引号字符串类似:
  // Conceptualizing, using an interpolation example to illustrate// how to think about "await" and "async" functions`code${await then-restart-point}more-code${await then-restart-point}`

单线使用Promises

const wait = t => new Promise(s => setTimeout(s, t, t));

带有中止信号的打字稿

const wait = (x: number, signal?: AbortSignal): Promise<number> => {return new Promise((s, f) => {const id = setTimeout(s, x, x);signal?.addEventListener('abort', () => {clearTimeout(id);f('AbortError');});});};

Demo

const wait = t => new Promise(s => setTimeout(s, t));// Usageasync function demo() {// Count downlet i = 6;while (i--) {await wait(1000);console.log(i);}// Sum of numbers 0 to 5 using by delay of 1 secondconst sum = await [...Array(6).keys()].reduce(async (a, b) => {a = await a;await wait(1000);const result = a + b;console.log(`${a} + ${b} = ${result}`);return result;}, Promise.resolve(0));console.log("sum", sum);}demo();

如果你想要在所有浏览器上都可用的代码,那么使用#0#1。如果你正在阅读这些答案,你可能会注意到接受的答案破坏了Internet Explorer 11中的所有JavaScript编译,使用这个解决方案后,似乎大约5%的用户仍在使用这种积极开发的浏览器并需要支持。

这几乎破坏了一切。有已知的报告称箭头函数破坏了DrupalWordPress亚马逊AWSIBM软件的Internet Explorer 11功能,甚至还有一个专用的关于Stack Overflow的讨论

只要检查一下…

浏览器兼容性图-箭头函数表达式

浏览器兼容性图-setTimeout

使用setTimeout()clearTimeout(),这将对所有浏览器起到作用…

工作JSBin演示

var timeout;
function sleep(delay) {if(timeout) {clearTimeout(timeout);}timeout = setTimeout(function() {myFunction();}, delay);}
console.log("sleep for 1 second");sleep(1000);
function myFunction() {console.log("slept for 1 second!");}

自2021年4月(Node.js16+)起,setTimeout()的新版本可用:

import { setTimeout } from 'timers/promises'
const res = await setTimeout(2000, 'result')
console.log(res);  // Prints 'result'

感谢@张一鸣,请看官方留档:https://nodejs.org/api/timers.html#timerspromisessettimeoutdelay-value-options

2021+更新

如果您正在寻找替代方案:

let sleep = ms => new Promise(res=>setTimeout(res,ms));

然后使用这个:

let sleep = async ms => void await Atomics.waitAsync(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms).value;

请注意,截至发布此问题时,它是第3阶段的提案。此外,它可能需要您的网站跨源隔离。要查看它是否在您的浏览器中工作,(在Stack Overflow上)请尝试以下操作:

let sleep = async ms => void await Atomics.waitAsync(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms).value;
void async function() {console.log(1);await sleep(2000);console.log(2);}()

什么是JavaScript版本的睡眠()?

这已经在目前接受的答案中得到了回答:

await new Promise(r => setTimeout(r, 1000));

两个异步函数同时运行

最好把它放在函数sleep()中,然后await sleep().
要使用它,需要一点上下文:

function sleep (ms) { return new Promise(r => setTimeout(r, ms)); }
(async function slowDemo () {console.log('Starting slowDemo ...');await sleep(2000);console.log('slowDemo: TWO seconds later ...');})();
(async function fastDemo () {console.log('Starting fastDemo ...');await sleep(500);for (let i = 1; i < 6; i++) {console.log('fastDemo: ' + (i * 0.5) + ' seconds later ...');await sleep(500);}})();
.as-console-wrapper { max-height: 100% !important; top: 0; }

Two asynchronous calls running in sequence – one after the other

But suppose slowDemo produces some result that fastDemodepends upon.
In such a case, slowDemo must run to completion before fastDemo starts:

function sleep (ms) { return new Promise(r => setTimeout(r, ms)); }
(async () => {await (async function slowDemo () {console.log('Starting slowDemo ...');await sleep(2000);console.log('slowDemo: TWO seconds later ... completed!');})();
(async function fastDemo () {console.log('Starting fastDemo ...');await sleep(500);let i = -2;for (i = 1; i < 5; i++) {console.log('fastDemo: ' + (i * 0.5) + ' seconds later ...');await sleep(500);}console.log('fastDemo: ' + (i * 0.5) + ' seconds later. Completed!');})();})();
.as-console-wrapper { max-height: 100% !important; top: 0; }

内胆:

(async () => await new Promise(resolve => setTimeout(resolve, 500)))();

这里的500是VM在移动到下一行代码之前等待的时间(以毫秒为单位)。

一点tldr;

基本上,当你创建一个Promise时,它会在创建时返回一个observable,在回调中给出解决的引用,该回调用于在可用时移交数据/响应。在这里,500毫秒后通过setTimeOut调用解决,在不执行解决之前,外部作用域正在等待进一步进行,因此,创建了一个假阻塞。这与非阻塞(或调用其他语言中可用的非线程保留睡眠)完全不同,因为线程,很可能是UI和网页/节点应用程序的任何其他正在进行的任务都将被阻塞,主线程将专门用于等待Promise解决。

JavaScript是一个单线程的执行环境。那里的每个函数都只由一个线程执行。要求“睡眠”意味着你想让整个VM实例停止几毫秒,我认为这在JavaScript世界中是一个非常现实的要求,因为如果执行线程被强制睡眠,不仅那个特定的函数,而且所有其他执行都会受到影响。

首先,实际上不可能让该线程休眠。你只能通过投入一些无所事事的工作来保持该线程忙碌。然而,如果你只想在一些计算中添加延迟,请将它们的执行放在单个函数上下文中,并让继续发生在该函数的setTimeout(或Promise,如果你喜欢)中。如果通过睡眠,你想延迟某些事情,否则是不可能的。

require('deasync').sleep(100);

如果您真的需要等待那么多秒,目前接受的使用async/awaitsetTimeout的解决方案是完美的。然而,如果您将其用于屏幕动画,您应该真正使用requestAnimationFrame()。这与setTimeout的功能非常相似,但只有当动画对用户可见时才调用回调。这意味着如果您在网站上运行动画并且用户切换选项卡,动画将暂停并节省电池寿命。

这是使用requestAnimationFramewait方法的实现。它接收许多帧,并在它们全部通过后解析:

const animationWait = (frames) =>new Promise((resolve) => {let framesPassed = 0;requestAnimationFrame(function loop() {if (++framesPassed >= frames) return resolve();requestAnimationFrame(loop);});});  
// typewriter effect for demonstrationconst content = document.querySelector(".content");
async function typeWriter(endText, wait) {content.textContent = "";for (const letter of endText) {content.textContent += letter;await animationWait(wait);}}
typeWriter("Okay. This simple typewriter effect is an example of requestAnimationFrame.", 8);
<p>The animation will play below; Try switching tabs and see thatthe animation pauses.</p><code class="content"></code>

阅读更多关于requestAnimationFrame

浏览器支持(IE10+)

这是睡眠的阻塞版本。在测试活动期间发现它更容易遵循,您需要顺序执行。它可以像sleep(2000)一样调用以使线程休眠2秒。

function sleep(ms) {const now = Date.now();const limit = now + ms;let execute = true;while (execute) {if (limit < Date.now()) {execute = false;}}return;}

天真地说,您可以使用与pausecomp函数相同的年间循环来实现sleep()(这基本相同):

const sleep = (seconds) => {const waitUntil = new Date().getTime() + seconds * 1000while(new Date().getTime() < waitUntil) {// do nothing}}

你可以像这样使用sleep()方法:

const main = () => {const a = 1 + 3
// Sleep 3 seconds before the next actionsleep(3)const b = a + 4
// Sleep 4 seconds before the next actionsleep(4)const c = b + 5}
main()

这是我想象你会如何使用睡眠功能,并且阅读起来相对简单。我借用了另一个帖子JavaScript中的睡眠-动作之间的延迟来展示你可能打算如何使用它。

不幸的是,您的计算机会变热,所有工作都将被阻止。如果在浏览器中运行,选项卡将停止运行,用户将无法与页面交互。

如果您将代码重构为异步,那么您可以利用设置超时作为与其他帖子相同的睡眠函数。

// define sleep using setTimeoutconst sleep = (seconds, callback) => setTimeout(() => callback(), seconds * 1000)
const main = () => {const a = 1 + 3let b = undefinedlet c = undefined
// Sleep 3 seconds before the next actionsleep(3, () => {b = a + 4
// Sleep 4 seconds before the next actionsleep(4, () => {c = b + 5})})}
main()

正如你所说,这不是你想要的。我从JavaScript中的睡眠-动作之间的延迟修改了示例以展示为什么会这样。随着添加更多操作,你要么需要将逻辑拉入单独的函数,要么越来越深地嵌套代码(回调地狱)。

为了解决“回调地狱”,我们可以使用承诺来定义睡眠:

const sleep = (seconds) => new Promise((resolve => setTimeout(() => resolve(), seconds * 1000)))
const main = () => {const a = 1 + 3let b = undefinedlet c = undefined
// Sleep 3 seconds before the next actionreturn sleep(3).then(() => {b = a + 4
// Sleep 4 seconds before the next actionreturn sleep(4)}).then(() => {c = b + 5})}
main()

Promise可以避免深度嵌套,但看起来仍然不像我们开始时的常规同步代码。我们希望编写看起来同步但没有任何缺点的代码。

让我们再次使用异步/等待重写我们的main方法:

const sleep = (seconds) => new Promise((resolve => setTimeout(() => resolve(), seconds * 1000)))
const main = async () => {const a = 1 + 3
// Sleep 3 seconds before the next actionawait sleep(3)const b = a + 4
// Sleep 4 seconds before the next actionawait sleep(4)const c = b + 5}
main()

使用async/wait,我们可以调用sleep(),就好像它是一个同步的阻塞函数一样。这解决了你在另一篇文章中使用回调解决方案时可能遇到的问题,并避免了长时间运行循环的问题。

2022年更新

只需使用此代码片段。

await new Promise(resolve => setTimeout(resolve, 2000));

我建议前Python开发人员使用此方法

const sleep = (time) => {return new Promise((resolve) => setTimeout(resolve, Math.ceil(time * 1000)));};

用法:

await sleep(10) // for 10 seconds

setTimeout是JavaScript异步方法的一部分(开始执行的方法及其结果将在未来某个时候返回到称为回调队列的组件,稍后执行)

您可能想要做的是将setTimeout函数包装在Promise中。

Promise示例:

const sleep = time => new Promise(res => setTimeout(res, time, "done sleeping"));
// using native promisessleep(2000).then(msg => console.log(msg));

异步/等待示例:

const sleep = time => new Promise(res => setTimeout(res, time, "done sleeping"));
// using async/await in top level(async function(){const msg = await sleep(2000);console.log(msg);})();

更多关于setTimeout可以找到这里

更安全的异步睡眠与更好的DX

我用睡眠来调试……我忘记使用wait太多次了。让我挠头。我在写下面的实时片段时忘记使用wait……不再!

如果你在1毫秒内运行两次,下面的睡眠函数会提醒你。如果你确定你使用了wait,它还支持传递一个相当参数。它不会抛出,所以作为sleep(s)的替代品应该是安全的。享受。

是的,实时片段中有一个JavaScript版本。

// Sleep, with protection against accidentally forgetting to use awaitexport const sleep = (s: number, quiet?: boolean) => {const sleepId = 'SLEEP_' + Date.now()const G = globalThis as anyif (G[sleepId] === true && !quiet) {console.error('Did you call sleep without await? use quiet to hide msg.')} else {G[sleepId] = true}return new Promise((resolve) => {!quiet && setTimeout(() => {delete G[sleepId]}, 1)setTimeout(resolve, (s * 1000) | 0)})}

// Sleep, with protection agains accidentally forgetting to use awaitconst sleep = (s, quiet) => {const sleepId = 'SLEEP_' + Date.now()const G = globalThisif (G[sleepId] === true && !quiet) {console.error('Did you call sleep without await? use quiet to hide msg.')} else {G[sleepId] = true}return new Promise((resolve) => {!quiet && setTimeout(() => {delete G[sleepId]}, 1)setTimeout(resolve, (s * 1000) | 0)})}
const main = async() => {console.log('Sleeping for 1 second...')await sleep(1)console.log('forgetting to use await...')sleep(99)sleep(99)await sleep(1, true)console.log('Happy developer!')}main()

与公认的更容易阅读相比:

const sleep = (s: number) =>new Promise((p) => setTimeout(p, (s * 1000) | 0))