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

时间:2019-07-10 05:19:57

标签: javascript synchronization setinterval

请在下面查看我的代码,我不知道为什么它会产生预期的输出。我认为我使用setInterval()和setTimeout的方式是错误的。不知何故,该过程不会从上到下按1个顺序进行。似乎有3个线程并行运行。我该如何解决?谢谢。

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

预期输出:

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

实际输出:

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

4 个答案:

答案 0 :(得分:2)

由于Javascript是异步的,因此您需要某种方式来等待每个间隔和超时完成,然后再运行下一个。

一种方法是使用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);
    })
  }
})();

答案 1 :(得分:1)

不知道您将用此代码完成什么。但请尝试以下方法。您可以控制台记录您的要求。做改变以您的喜好,

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

答案 2 :(得分:1)

JavaScript无法以这种方式工作。您需要首先了解ASYNC操作和回调的概念。 Aysnc操作(如setTimeout和setInterval)在移动到代码的下一行之前,不必等待其回调函数完成。他们只是将执行光标移到下一行。您的setInterval函数将在1000毫秒后完成其回调执行。

添加了新功能,例如等待和异步功能。您可能希望研究它们以实现所需的目标。

您正在运行的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);
})();

答案 3 :(得分:1)

您有一个forEach循环,该循环将循环3次。在第一次迭代中,它将:

  1. console.log框架(1)
  2. 创建一个间隔,将在1秒内执行
  3. 创建将在2秒钟内执行的超时

然后,循环的第二次迭代会在第一次迭代后立即发生,因此它将再次发生:

  1. console.log框架(2)
  2. 创建另一个新的第二个间隔,该间隔将在1秒内执行
  3. 创建另一个新的第二次超时,该超时将在2秒内执行

最后,第三次迭代将立即发生,它将:

  1. console.log框架(3)
  2. 创建另一个新的间隔,将在1秒内执行
  3. 创建另一个新的第三次超时,将在2秒内执行

接下来,所有新创建的三个时间间隔将在循环结束后约1秒执行。每个时间间隔将比前一个时间间隔稍稍执行。每个变量都在变量frame周围包含一个“闭包”(即,当它们被创建时,它们都被“捕获”在设置为0的帧中,因此它们都console.log(0)

在下一秒,这3个间隔中的每一个将尝试再次运行(现在每个间隔都带有frame === 1),并且3个超时也将尝试运行。请注意,每个超时还形成了一个“关闭”,在创建之时将e的值锁定。您最终会得到一些间隔的执行时间,并混合了超时的执行时间。

这3次超时仅一次发生。

输出的其余部分是连续执行的3个间隔的集合,每个集合之间有2秒的间隔。


您只需使用一个间隔(无循环),设置为每秒触发并打印一些内容,即可实现输出。我不确定要打印这些语句间隔几秒的要求,因此我无法生成所需的确切代码,但是有些东西会在最佳时机生成您想要的输出:

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