📜  foreach 中的 js 等待 - Javascript (1)

📅  最后修改于: 2023-12-03 15:15:10.462000             🧑  作者: Mango

foreach 中的 js 等待

在 Javascript 中,我们常常使用 foreach 来遍历数组或对象。然而,在一些特殊情况下,我们需要等待某些操作完成之后才能继续迭代。本文将介绍在 foreach 中实现等待的方法。

问题分析

foreach 中等待的主要场景为异步操作,例如通过 Ajax 请求获取数据。由于异步操作需要一定的时间,而 foreach 循环则是同步迭代,在异步操作未完成时,继续迭代将会导致数据错误或程序异常。

先决条件

在介绍等待方法之前,我们需要先了解异步编程的两种基本实现方式:回调函数和 Promise。本文将混用两种方式,因此读者需对两者都有一定的了解。

回调函数的实现

在使用回调函数时,我们需要将 foreach 中的迭代操作放到回调函数中。在每次迭代结束后,再递归调用回调函数进行下一轮迭代。在这个过程中,我们需要同步等待异步操作完成后再进行下一轮迭代。

function iterateWithCallback(arr, callback, index = 0) {
  if (index >= arr.length) {
    return;
  }
  callback(arr[index], index, arr, () => {
    iterateWithCallback(arr, callback, index + 1);
  });
}

iterateWithCallback([1, 2, 3], (value, index, array, next) => {
  console.log(value);
  setTimeout(next, 1000);
});

在上述代码中,我们定义了一个名为 iterateWithCallback 的函数,它接受三个参数:待遍历的数组(或类数组对象)、迭代操作的回调函数和迭代的起始下标(默认为 0)。在函数内部,我们首先判断是否已经迭代完成,如果是则返回。否则,我们调用回调函数,并将下一轮迭代的操作放在回调函数的最后一个参数中传入。由此实现了同步等待异步操作的目的。

上述代码中,回调函数中的 setTimeout 模拟了一个异步操作。在实际应用中,可以将其替换为 Ajax 请求或其他异步操作。

Promise 的实现

在使用 Promise 时,我们可以使用 async/await 将异步操作转换为同步操作,从而在 foreach 中直接使用。下面是示例代码:

async function asyncForEach(arr, callback) {
  for (let i = 0; i < arr.length; i++) {
    await callback(arr[i], i, arr);
  }
}

(async function () {
  const arr = [1, 2, 3];
  await asyncForEach(arr, async (value) => {
    console.log(value);
    await new Promise((resolve) => setTimeout(resolve, 1000));
  });
})();

在上述代码中,我们首先定义了一个名为 asyncForEach 的函数,它接受两个参数:待遍历的数组(或类数组对象)和以 Promise 形式返回的迭代操作的回调函数。在函数内部,我们使用 for 循环遍历数组,使用 await 等待 Promise 完成后再进行下一轮迭代。

在实现中,我们使用了立即执行函数和 Promise 的方式,从而可以在顶层作用域中使用 await。所以,在实际应用中,可以将 asyncForEach 定义为一个普通的函数,以便于其他地方的调用。

结论

foreach 循环中等待异步操作有多种实现方式,回调函数和 Promise 是常用的两种方式。以 Promise 实现更加简洁易懂,但需要先理解 async/await 的语法。回调函数实现则需要额外的回调处理,并且代码结构会较为复杂。在实际应用中,可以根据具体情况选择适合的实现方式。