0

在一次采访中,我有以下问题。看不出有什么问题。

以下代码尝试顺序运行 10 个任务,并在每个任务后超时 1 秒。给定以下一段代码,请找出其中的问题,并为初衷编写一个正确的实现。

for (let i = 0; i < 10; i++) {
  setTimeout(function() {
    // Running some asynchronous tasks here
    // ...
    console.log("completed task id " + i);
  }, 1000)
}

4

4 回答 4

2

这会在循环运行时立即启动所有超时,因此所有消息都将在 1 秒内,而不是它们之间的 1 秒。

解决它的一种方法是使超时取决于i.

for (let i = 0; i < 10; i++) {
  setTimeout(function() {
    // Running some asynchronous tasks here
    // ...
    console.log("completed task id " + i);
  }, 1000 * (i + 1))
}

这是最简单的方法,它在前一个任务开始后 1 秒启动每个任务。

但是,如果任务执行了一些长时间的操作,并且您不想在前一个任务完成 1 秒后开始下一个任务那么您将需要更复杂的实现。您必须让任务递增i并调用setTimeout()自身来安排下一次迭代,而不是使用循环。

function timeout_fn(i) {
  // do slow operation
  console.log("completed task id " + i);
  i++;
  if (i < 10) {
    setTimeout(() => timeout_fn(i), 1000);
  }
}

setTimeout(() => timeout_fn(0), 1000);

于 2020-01-16T17:22:56.097 回答
2

您可以尝试使用异步功能等待承诺将得到解决。

async function toDo() {
  for (let i = 0; i < 10; i++) {
    await new Promise(res => {
      setTimeout(() => {
        // Running some asynchronous tasks here
        // ...
        console.log('completed task id ' + i)
        res()
      }, 1000)
    })
  }
}

toDo()

于 2020-01-16T17:32:47.183 回答
1

问题:

  • setTimeout安排一个函数在指定的延迟后运行。请注意,所有这些setTimeouts都是同时安排的,它们不会相互等待。这就是“异步”的含义。因此,您所有的setTimeout调用都有1000毫秒的延迟,并且它们都将在 1000 毫秒后连续运行。
  • 如果你真的在回调中运行其他异步任务setTimeout,console.log 将不会等待它们,除非你告诉它。我只能猜测,但请确保您使用await、 异步函数或其他回调。

for (let i = 0; i < 10; i++) {
  setTimeout(function() {
    // Running some asynchronous tasks here
    // ...
    console.log("completed task id " + i);
  }, 1000 * i) //multiply i by 1000 to wait 1,2,3,4... seconds
}

于 2020-01-16T17:25:11.560 回答
1

也许另一种解决方案是使用具有 1000 毫秒间隔的 setInterval 函数,并以 10 秒的等待时间调用 setTimeout 来清除间隔:

const myInterval = setInterval(function() {
  // some async stuff here
  
}, 1000);

setTimeout(function() {
  clearInterval(myInterval)
}, 10000);

于 2020-01-16T17:34:19.440 回答