等待5秒钟,然后执行下一行


311

下面的此功能无法正常运行。作为JS新手,我不知道为什么。

我需要等待5秒钟,然后再检查是否newState-1

目前,它不会等待,它会立即进行检查。

function stateChange(newState) {
  setTimeout('', 5000);

  if(newState == -1) {
    alert('VIDEO HAS STOPPED');
  }
}

Answers:


323

您必须将代码放入提供给的回调函数中setTimeout

function stateChange(newState) {
    setTimeout(function () {
        if (newState == -1) {
            alert('VIDEO HAS STOPPED');
        }
    }, 5000);
}

任何其他代码将立即执行。


4
主要问题在于,在某些情况下(特别是测试),这是远远不够的。如果您需要从函数返回之前休眠500ms,例如模拟一个缓慢的异步http请求,该怎么办?
A.Grandt

14
如果用“测试”来表示单元测试:您的测试框架应具有运行异步测试的方法。如果您要进行手动测试,则:Chrome的“网络”标签上有一个“限制”下拉菜单,可模拟缓慢的请求。
约瑟夫·西尔伯

1
如果我开发了chrome扩展名,并且注入脚本中的最后一个评估值应该给我结果怎么办?我需要一些延误吗?
mirek '19

182

您实际上不应该这样做,正确使用超时是解决OP问题以及在一段时间后只想运行某些东西的正确工具。约瑟夫·西尔伯(Joseph Silber)的回答很好地证明了这一点。但是,如果在某些非生产情况下您确实想将主线程挂起一段时间,则可以这样做。

function wait(ms){
   var start = new Date().getTime();
   var end = start;
   while(end < start + ms) {
     end = new Date().getTime();
  }
}

以以下形式执行:

console.log('before');
wait(7000);  //7 seconds in milliseconds
console.log('after');

我到达这里是因为我正在构建一个简单的测试用例,用于对长时间运行的阻塞操作(即昂贵的DOM操作)周围的异步操作进行排序,这是我的模拟阻塞操作。它非常适合该工作,因此我想将它发布给其他有类似用例的人。即使这样,它也会在while循环中创建一个Date()对象,如果它运行足够长的时间,可能会使GC感到不知所措。但是我不能强调太多,这仅适合测试,要构建任何实际功能,应参考Joseph Silber的答案。


7
这不会停止javascript执行。
特里·林

23
@TerryLin尝试运行它。
麦克风

6
所以基本上您是在浪费CPU时间。这不是等待,因为您没有将线程置于睡眠模式,从而使主处理器可以专注于其他任务。
Kyordhel '17

6
@Gzork线程睡眠只是实现等待功能的一种方法,不幸的是,它在客户端javascript上下文中不可用。但是,如果您认为客户端中的其他异步任务将在其运行时完成,则显然您尚未对其进行测试。尽管我将在主线程中使用它,但我整理了一个小提琴,说明即使首先通过setTimeout调用它,它仍然会中断其他异步事件jsfiddle.net/souv51v3/1-您甚至会发现JSFiddle窗口本身在完成时变得无响应。
Mic

1
糟糕的解决方案恕我直言-在CPU处于“睡眠”状态时会占用CPU。正确的睡眠方式是通过async / await ala这个答案stackoverflow.com/questions/951021/…或Etienne's。
David Simic '18

162

这是使用新的async / await语法的解决方案。

确保检查浏览器支持,因为这是ECMAScript 6引入的新功能。

实用功能:

const delay = ms => new Promise(res => setTimeout(res, ms));

用法:

const yourFunction = async () => {
  await delay(5000);
  console.log("Waited 5s");

  await delay(5000);
  console.log("Waited an additional 5s");
};

这种方法的优势在于,它使您的代码外观和行为类似于同步代码。


不需要ECMAScript 6:如果您已经在使用Promise进行异步加载,并且只想模仿链条的一部分而花费很长时间,则可以将此wait()函数添加到链条中。
Dovev Hefetz '18

2
这确实是使用新语法的最佳答案。我在使用上面的wait()解决方案时遇到问题。
pianoman102 '19


36

您不应该只是尝试在javascript中暂停5秒钟。那样行不通。您可以安排一个代码功能从现在开始运行5秒钟,但是您必须将要稍后运行的代码放入一个功能中,该功能之后的其余代码将立即继续运行。

例如:

function stateChange(newState) {
    setTimeout(function(){
        if(newState == -1){alert('VIDEO HAS STOPPED');}
    }, 5000);
}

但是,如果您有这样的代码:

stateChange(-1);
console.log("Hello");

console.log()语句将立即运行。它不会等到stateChange()函数中的超时触发后才开始。您不能仅在预定时间内暂停javascript执行。

相反,您要运行的任何代码延迟都必须在setTimeout()回调函数内部(或从该函数调用)。

如果您确实尝试通过循环“暂停”,那么您实际上将“挂起” JavaScript解释器一段时间。由于Javascript仅在单个线程中运行代码,因此在循环时,其他任何东西都无法运行(无法调用其他事件处理程序)。因此,循环等待某些变量更改将永远无法进行,因为没有其他代码可以运行来更改该变量。


31
您不能仅在预定的时间内暂停javascript执行。我认为您的意思是不应该这样做,因为您可以(如果您想吊死自己的话):var t = new Date().getTime(); while (new Date().getTime() < t + millisecondsToLockupBrowser);
Joseph Silber 2013年

9
@JosephSilber-好的,您可以这样做,但是在实践中,由于许多浏览器都会显示一个对话框,提示脚本无响应,这是一种可怕的用户体验,对电池寿命不利,因此该页面这样做时挂了……那将是不好的。
jfriend00

12
,当然,这将是可怕的,没有人应该永远永远永远永远永远永远做到这一点。我只是无法抗拒我的内心“精心实际”。抱歉。
约瑟夫·席尔伯

31

如果您使用的是异步功能,则只需一行即可:

console.log(1);
await new Promise(resolve => setTimeout(resolve, 3000)); // 3 sec
console.log(2);

注意,如果目标是NodeJS,则使用它的效率更高(这是一个预定义的setTimeout函数):

await setTimeout[Object.getOwnPropertySymbols(setTimeout)[0]](3000) // 3 sec

两种实现之间有什么区别?
EAzevedo

1
目前,没有区别。但是,如果某个时候节点将决定使其更快/更安全/更高效,那么您将预先使用node js版本。尽管对于大多数人而言,能力更可能是关键因素,但在这种情况下,您最好使用第一种方法。
Shl

谢谢。您的回答解决了我已经面临三天的问题。谢谢。
EAzevedo

8

尝试这个:

//the code will execute in 1 3 5 7 9 seconds later
function exec() {
    for(var i=0;i<5;i++) {
        setTimeout(function() {
            console.log(new Date());   //It's you code
        },(i+i+1)*1000);
    }
}

7

创建这样的函数的最佳方法是等待毫秒,此函数将等待参数中提供的毫秒:

function waitSeconds(iMilliSeconds) {
    var counter= 0
        , start = new Date().getTime()
        , end = 0;
    while (counter < iMilliSeconds) {
        end = new Date().getTime();
        counter = end - start;
    }
}


3

根据Joseph Silber的回答,我会那样做,比较通用。

您将拥有自己的功能(让我们根据问题创建一个):

function videoStopped(newState){
   if (newState == -1) {
       alert('VIDEO HAS STOPPED');
   }
}

您可以拥有一个等待功能:

function wait(milliseconds, foo, arg){
    setTimeout(function () {
        foo(arg); // will be executed after the specified time
    }, milliseconds);
}

最后,您将拥有:

wait(5000, videoStopped, newState);

那是一个解决方案,我宁愿不要在wait函数中使用参数(仅使用foo();代替foo(arg);),但这只是示例。


3

此解决方案来自React Native的文档,用于刷新控件

function wait(timeout) {
    return new Promise(resolve => {
        setTimeout(resolve, timeout);
    });
}

要将其应用于OP的问题,可以与以下功能配合使用此功能await

await wait(5000);
if (newState == -1) {
    alert('Done');
}

1

您可以通过对函数进行少量更改(async和await)来增加延迟。

const add5SecondsDelay = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('5 seconds');
    }, 50000);
  });
}

async function asyncFunctionCall() {

  console.log("stpe-1"); 
  const result = await add5SecondsDelay ();
  console.log("step-2 after 5 seconds delay"); 

}

asyncFunctionCall();

-2

使用angularjs:

$timeout(function(){
if(yourvariable===-1){
doSomeThingAfter5Seconds();
}
},5000)

-2

创建新的Js函数

function sleep(delay) {
        var start = new Date().getTime();
        while (new Date().getTime() < start + delay);
      }

要延迟执行时,请调用该函数。将int的毫秒数用作延迟值。

####Some code
 sleep(1000);
####Next line

3
那会消耗太多资源。
awavi

-2

我用它从Edge或IE运行PC游戏。并在7秒钟后自动关闭IE Edge。

Firefox和Google Chrome无法以这种方式启动游戏。

<html<body>
<a href="E:\game\game.exe" name="game" onmouseout="waitclose(7000);"> game
<img src="game.jpg" width="100%" height="97%" ></a>
<script>
function waitclose(ms){
 var start = new Date().getTime();var end=start;
 while(end < start + ms) {end = new Date().getTime();}
window.open('', '_self', ''); window.close();
}
</script>
</body></html>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.