简体   繁体   English

JavaScript:setInterval()无法产生预期的输出

[英]JavaScript: setInterval() doesn't produce expected output

Please take a look at my code below, I don't know why it produce expected output. 请在下面查看我的代码,我不知道为什么它会产生预期的输出。 I think the way I used setInterval() and setTimeout is wrong. 我认为我使用setInterval()和setTimeout的方式是错误的。 Somehow the process doesn't go by 1 order from top to bottom. 不知何故,该过程不会从上到下按1个顺序进行。 It seems like there are 3 threads run in parallel. 似乎有3个线程并行运行。 How can I fix it? 我该如何解决? Thank you. 谢谢。

 (function() { var nums = [1, 2, 3]; nums.forEach( (e) => { console.log(e); var frame = 0; let loop = setInterval(function() { if (frame === 3) clearInterval(loop); console.log(e + " frame " + frame); frame++; }, 1000); let wait = setTimeout(function() { console.log(e + " 2 second passed"); }, 2000); } ) })(); 

Expected output: 预期产量:

1
1 frame 0
1 frame 1
1 frame 2
1 2 seconds passed
2
2 frame 0
2 frame 1
2 frame 2
2 2 seconds passed
3
3 frame 0
3 frame 1
3 frame 2
3 2 seconds passed

Actual output: 实际输出:

1
2
3
1 frame 0
2 frame 0
3 frame 0
1 frame 1
1 2 second passed
2 frame 1
2 2 second passed
3 frame 1
3 2 second passed
1 frame 2
2 frame 2
3 frame 2
1 frame 3
2 frame 3
3 frame 3

Because Javascript is asynchronous, you need some way of waiting for each of the intervals and the timeout to complete before running the next. 由于Javascript是异步的,因此您需要某种方式来等待每个间隔和超时完成,然后再运行下一个。

One way of doing this is by using async/await and wrapping the intervals and timeout in a promise . 一种方法是使用async / await并将时间间隔和超时包装在promise中

 (async function() { var nums = [1, 2, 3]; for (const e of nums) { console.log(e); let frame = 0; await new Promise(resolve => { let loop = setInterval(function() { if (frame === 3) { clearInterval(loop); resolve(); } else { console.log(e + " frame " + frame); frame++; } }, 100); }) await new Promise(resolve => { let wait = setTimeout(function() { console.log(e + " 2 second passed"); resolve(); }, 200); }) } })(); 

No idea what you going to accomplished with this code. 不知道您要用此代码完成什么。 but please try with below approach. 但请尝试以下方法。 you can console log what you asked. 您可以控制台记录您的要求。 Do changes as your favor, 做改变,如你所愿,

 let nums = [1, 2, 3]; const timesecs = 1000; const timeOut = (num) => { setTimeout( () => { console.log(num); nums.forEach( (item, index) => { console.log(num + " frame " + index); } ) //console.log(`${num} ${num+1} seconds passed`); console.log(`${num} 2 seconds passed`); }, num * timesecs ) } nums.forEach((num) => { timeOut(num); }); 

Javascript doesn't work this way. JavaScript无法以这种方式工作。 You need to understand the concept of ASYNC operations and callbacks first. 您需要首先了解ASYNC操作和回调的概念。 Aysnc operations, like setTimeout and setInterval, do not wait for their callback functions to finish before moving to the next line of the code. Aysnc操作(如setTimeout和setInterval)在移动到代码的下一行之前,不必等待其回调函数完成。 They just move the execution cursor to the next line. 他们只是将执行光标移到下一行。 Your setInterval function will finish its callback execution after 1000 milliseconds. 您的setInterval函数将在1000毫秒后完成其回调执行。

There are new functionalities are added like await and async function. 添加了新功能,如等待和异步功能。 You may want to look into them to achieve what you want. 您可能希望研究它们以实现所需的功能。

The for loop you are running should be inside the interval rather than what you are doing. 您正在运行的for循环应该在时间间隔内,而不是您在做什么。

 (function () { var nums = [1, 2, 3]; var ind = 0; let loop = setInterval(function(){ if(ind === 2){ clearInterval(loop); } console.log(nums[ind]); nums.forEach(e => { console.log(nums[ind] + " frame " + e); }); console.log(nums[ind] + " 2 seconds passed"); ind++; }, 2000); })(); 

You have a forEach loop that will loop 3 times. 您有一个forEach循环,该循环将循环3次。 On the first iteration, it will: 在第一次迭代中,它将:

  1. console.log the frame (1) console.log框架(1)
  2. create an interval that will execute in 1 second 创建一个间隔,将在1秒内执行
  3. create a timeout that will execute in 2 seconds 创建将在2秒内执行的超时

Then the second iteration of the loop happens immediately after the first iteration so it will again: 然后,循环的第二次迭代将在第一次迭代之后立即发生,因此它将再次发生:

  1. console.log the frame (2) console.log框架(2)
  2. create another new second interval that will execute in 1 second 创建另一个新的第二个间隔,将在1秒内执行
  3. create another new second timeout that will execute in 2 seconds 创建另一个新的第二个超时,将在2秒内执行

Finally the third iteration will occur, immediately and it will: 最后,第三次迭代将立即发生,它将:

  1. console.log the frame (3) console.log框架(3)
  2. create another third new interval that will execute in 1 second 创建另一个第三个新间隔,将在1秒内执行
  3. create another third new timeout that will execute in 2 seconds 创建另一个新的第三次超时,将在2秒内执行

Next, all three of your newly created intervals will execute about 1 second after the loop finishes. 接下来,所有新创建的三个时间间隔将在循环结束后约1秒执行。 Each interval will execute very slightly behind the previous interval. 每个时间间隔将比前一个时间间隔稍稍执行。 And each one contains a "closure" around the variable frame (ie when they were created, they all "captured" frame when it was set to 0 so they all console.log(0) . 每个变量在变量frame周围都包含一个“封闭”(即,当它们被创建时,当将其设置为0时,它们都“捕获”了框架,因此它们都为console.log(0)

On the next second, each of the 3 intervals will attempt to run again (now each with frame === 1 ), and the 3 timeouts will also attempt to run. 在下一秒,这3个间隔中的每个间隔将尝试再次运行(现在每个间隔都具有frame === 1 ),并且3个超时也将尝试运行。 Note that each timeout also has formed a "closure", locking in the value of e at the time it was created. 请注意,每个超时还形成了一个“关闭”,在创建e时将其值锁定。 You end up getting a bit of staggering of intervals executing, mixed with timeouts executing. 您最终会得到一些交错的执行间隔,并混合执行超时。

The 3 timeouts only ever happen once each. 3个超时仅一次发生一次。

The remainder of the output is the set of 3 intervals successively executing, with a 2 second gap between each set. 输出的其余部分是连续执行的3个间隔的集合,每个集合之间有2秒的间隔。


You could achieve your output by just using one interval (with no loop), set to fire every second and print something. 您只需使用一个间隔(无循环),设置为每秒触发一次并打印一些内容,即可实现输出。 I'm not sure of the requirements regarding how many seconds apart you need these statements to be printed, so I cannot produce the exact code that you need but here's something that produces your desired output with my best guess at the timing: 我不确定要打印这些语句间隔多少秒的要求,因此我无法生成所需的确切代码,但以下内容可以根据您的最佳猜测生成所需的输出:

var num = 1;
var frame = 0;
var loop = setInterval( function() {
  if (frame === 0) {
    console.log(num);
  }
  if (frame >= 0 && frame <= 2) {
    console.log(num + " frame " + frame);
  }

  if (frame === 4) {
    console.log(num + " 2 seconds passed");
    num++;
    frame = -1;
  }
  if (num > 3) {
    clearInterval(loop);
  }
  frame++;
}, 1000);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM