如何在运行下一段代码之前等待异步JSZip .forEach()调用完成?

8

我有一个名为'data'的全局变量,它在forEach循环内被修改。然而,由于循环是异步的,代码不会等到数据填充完毕才继续执行。这是使用JSZip库时出现的情况。

let data = [];

await zip.folder("folderName").forEach(async function (relativePath, file) {
            let json = await zip.file(file.name).async("text");
            data.push(json);
            console.log(data.length); // prints increasing numbers
        });

console.log(data.length); //prints 0
// need to do something with data but it is empty

在继续执行代码之前,我该如何等待数据数组被填充?


查看 API,forEach 看起来不是异步的,因此向其发送 promise 不起作用,它期望一个回调函数。 - Keith
1
可能是如何等待一组异步回调函数?等许多其他问题的重复。 - JJJ
@JJJ 不完全是这样。大多数答案和“许多其他答案”都会建议使用map(),但在这里不是一个选项,或者手动使用for循环迭代集合,但在没有对API内部进行假设的情况下也不可能实现。 - Patrick Roberts
我看不出为什么这里不能使用map。 - JJJ
@JJJ 在盲目关闭之前可能需要查看 API。返回值不是一个数组,而是一个特定于 API 的对象。 - Patrick Roberts
2个回答

9

forEach()没有返回值,因此无法等待。您必须从每个ZipObject#async()中填充一个promise数组,并使用Promise.all()等待该数组的结果:

const promises = [];

zip.folder("folderName").forEach(function (relativePath, file) {
  promises.push(zip.file(file.name).async("text"));
});

Promise.all(promises).then(function (data) {
  // do something with data
});

4
根据JSZip文档,似乎没有办法将forEach(callback)转换为Promise数组。所以我想到的唯一方法是获取文件数量并使用计数器。
const myFolder = zip.folder("folderName");
const numberOfCallbacks = Object.keys(myFolder.files).length - 1;
let counter = 0;
myFolder.forEach((relativePath, file) => {
    // your code. you'd better create a Promise here and add it to an array of promises.
    counter++;
    if (counter === numberOfCallbacks) {
        // everything is done. If you created Promise above, here you can use Promise.all()
    }
});

我测试了上述代码,它可以正常工作。如果有问题,请告诉我。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接