循环和异步问题

129 阅读2分钟

今天遇到个问题,想让for循环结束了再resolve(arr)。
但后面这些代码好像只执行了一次,最开始以为是for循环只执行了一次,后面发现应该是forEachawait的锅,执行请求时已经是循环的最后一次,await没起作用。

    async function uploadChunk() {
        return new Promise(async (resolve, reject) => {
            await handleFileChange();
            console.log('formDataArr', formDataArr);
            let arr = [];
            let counter = 0;
            for (let index = 0; index < formDataArr.length; index++) {
                console.log('index', index);
                const items = formDataArr[index];
                 formDataArr[index].forEach((item) => {
                    try {
                        // const res = await axios.get("/uploadFile");
                        const res = await uploadFile(item.get("file"), item.get("name"), item.get("chunks"), item.get("chunk"));
                        console.log('uploadFile-res', res);
                        if (item.get("chunks") - 1 == item.get("chunk")) {
                            arr.push(res.data);  // 分片后最终结果
                        }
                        counter++;
                        if (counter === formDataArr.length) {
                            resolve(arr); // 当计数器等于数组长度时,所有操作都完成,调用 resolve
                        })
                    } catch (error) {
                        reject(error);
                        return;
                    }
                }
            }
        })
    }

循环可能只执行了一次的原因是异步操作的执行顺序导致的。

在这段代码中,formDataArr[index].forEach 中的回调函数是异步的。当你遍历 formDataArr 中的第一个元素时,在执行 formDataArr[index].forEach 时,内部的异步操作 axios.get("/uploadFile") 开始执行,但是并没有等待异步操作完成,而是继续执行循环的下一个迭代。

因为循环的第二次迭代是在异步操作还没完成的情况下开始的,第一个异步操作可能还没有机会执行完成。所以,整个循环可能会很快的完成并退出,而不是等待异步操作的结果。

为了确保循环正确执行和等待所有异步操作完成,可以将 forEach 循环改为 for...of 循环,以便可以使用 await 关键字等待每个异步操作完成。修改后的代码如下:

for (let index = 0; index < formDataArr.length; index++) {
  console.log('index', index);
  const items = formDataArr[index];
  for (const item of items) {
    try {
      const res = await axios.get("/uploadFile");
      console.log('uploadFile-res', res);
      if (item.get("chunks") - 1 == item.get("chunk")) {
        arr.push(res.data);  // 分片后最终结果
      }
      counter++;
      console.log('counter', counter);
      console.log('formDataArr.length', formDataArr.length);
      if (counter === formDataArr.length) {
        resolve(arr); // 当计数器等于数组长度时,所有操作都完成,调用 resolve
      }
    } catch (error) {
      reject(error);
      return;
    }
  }
}

通过使用 for...of 循环,可以确保在每次迭代中都等待异步操作的完成,以及避免了可能导致循环直接退出的问题。这样,你就可以正确执行多次循环,并等待所有异步操作完成后再调用 resolve

总结:forEach不能支持异步调用,解决这个方法就是将forEach方法换成普通for循环/for of就可以了