循环内使用dispatch,但只执行一次bug

62 阅读2分钟

原因:在JavaScript中,当使用循环执行异步操作时,循环会非常快速地运行完毕,而不会等待每个异步操作完成后再执行下一次循环。这意味着在循环中触发的多个异步操作会同时开始执行,而不会等待前一个异步操作完成。

因此,当在for循环中执行多次异步操作时,所有这些异步操作几乎同时开始执行,而在它们完成之前,for循环已经迭代完成。这就解释了为什么只有最后一次异步操作生效,因为在for循环内部所有的异步操作都被同时触发,但由于循环非常快速,所以它们实际上是并行执行的。

要解决这个问题,可以将异步操作放入一个闭包中,以便在每次迭代中创建一个新的作用域来保留循环变量的值。另外,也可以使用async/await或Promise.all()来确保所有的异步操作完成后再继续执行后续代码。

解决:

//方法一:使用了一个立即执行函数(IIFE)来创建一个新的作用域,并将当前迭代的索引值作为参数传递给该函数。这样,每次循环迭代时,都会为setTimeout函数创建一个新的作用域,并且每个异步操作都会在不同的作用域中执行,从而保证了正确的输出顺序。
const arr = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i++) {
  (function(index) {
    setTimeout(function() {
      console.log(arr[index]);
    }, 1000 * (index + 1));
  })(i);
};
//方法二:将循环体放入一个异步函数executeAsyncOperations()中,并使用await关键字等待每个异步操作完成。通过在每次迭代中等待Promise对象的解析,我们可以确保每个异步操作都完成后再执行下一次迭代。
const arr = [1, 2, 3, 4, 5];
async function executeAsyncOperations() {
  for (let i = 0; i < arr.length; i++) {
    await new Promise(resolve => {
      setTimeout(function() {
        console.log(arr[i]);
        resolve();
      }, 1000 * (i + 1));
    });
  }
}
executeAsyncOperations();