关于异步函数的问题以及我应该如何正确 运行 它同步

Problem regarding an asynchronous function and how I should correctly run it synchronously

我有以下算法:

// Main Function
    // Get some local data
    // Convert to some format I need to edit
    // Loop through user's local images
        // Edit the converted data to add the image's names to it
        // Convert IMAGE to base64 and add result into zip file
        that.uriToBase64(imageFilePath).then((result) => {
            console.log("image as base64: ", result);
            zip.file(arrayItem2.name, result, {base64: true});
        });

    // Convert data again to save it
    // Add data to zip file
    // Generate zip file and save it in user's local storage

//uriToBase64() function

我的问题

“将数据添加到 zip 文件”步骤发生在将图像添加到 zip 文件之前。虽然“Convert IMAGE to base64”这一步有一个.then,但里面的一切只有在一切都完成之后才会发生。在这种情况下,我的 zip 文件在没有图像的情况下被保存。我尝试以无数种方式使用 async/await 语法使这一步同步工作,但我无法按照预期的方式工作,即在每次迭代中将图像数据添加到 zip 文件中。

由于 uriToBase64() 函数的结果是 Promise,使用 .then 获取结果数据应该“暂停”循环,直到数据被 zip.file() 命令添加,然后迭代下一张图片,对吧?如果不是,考虑到算法的当前结构,等待它的正确方法是什么?


尝试次数

尝试 1

我尝试了一些令人讨厌的事情来完成这项工作,但又一次失败了。 我的新算法:

// Main Function
    // Get some local data
    // Convert to some format I need and add to a global variable
    // Loop through user's local images
        // Add +1 to new global variable 'imageCounter'
        // Edit the converted data (now in global variable) to add the image's names to it
        // Convert IMAGE to base64 and add result into zip file
        that.uriToBase64(imageFilePath).then((result) => {
            console.log("image as base64: ", result);
            zip.file(arrayItem2.name, result, {base64: true});
            that.prepareForWrite();

            // Check if this is the last iteration and run function again.
            if (thisIsLastIteration == true) { that.prepareForWrite(); }                        
        });

//prepareForWrite() function
    // imageCounter - 1
    // if imageCounter < 1
        // Convert data again to save it
        // Add data to zip file
        // Generate zip file and save in user's local storage

//uriToBase64() function

这样我正确地接收了所有数据,但是“生成 zip 文件并将其保存在用户的本地存储中”只添加了第一张图像,结果损坏了。

尝试 2

正如我之前所说,我已经用 async/await 尝试了很多。我还将整个功能分成更小的功能,并尝试 async/await 我需要先完成的部分。我最后一次尝试使用 async/await 看起来与此类似:

// async Main Function
    // Get some local data
    // Convert to some format I need to edit
    // Loop through user's local images
        // Edit the converted data to add the image's names to it
        // Convert IMAGE to base64 and add result into zip file
        let result = await that.uriToBase64(imageFilePath);
                console.log(result);
                zip.file(arrayItem2.name, result, {base64: true});

    // Convert data again to save it
    // Add data to zip file
    // Generate zip file and save it in user's local storage

//uriToBase64() function

尝试 3

好的,经过一些测试后,我能够以几种不同的方式从 uriToBase64() 函数同步获取数据。无论我如何接收 base64 字符串,生成 ZIP 文件后的结果始终相同:文件中只有一张压缩和损坏的图像,其他图像和主文件被忽略。

这让我想知道:也许问题是在生成 ZIP 文件之前如何压缩文件。所以我找到了这个问题的一些答案。我发现 JSZIP 库中包含一个函数,据我所知,它允许检查已添加到 ZIP 文件中的内容。考虑到这一点,我寻找了一些相关的问题,这让我想到了这个 。在这种情况下,每次添加文件时,相同的函数returns文件完成响应。

这是我尝试做的:

mainFunction() {
    let string64 = 'veryLongBase64String';

    let b64s = [];
    let arrayOfPromises = [];

    b64s.push(string64);
    b64s.push(string64);
    console.log(b64s);

    b64s.forEach((b64, index) => {
        let fileName = index + ".jpg";
        arrayOfPromises.push(this.addFileToZip(fileName, b64)); 
    });

    Promise.all(arrayOfPromises)
    .then(this.zip.generateAsync({type:"blob"})
        .then((content) => {
            let filePath = this.file.externalRootDirectory + '/app_downloads/';
            this.file.writeFile(filePath, "testZip.zip", content).then(() => {
                alert("File saved!");
            })
            .catch((err) => {
                alert("Error while creating file: " + JSON.stringify(err));
            });
        })
    );
}

addFileToZip(name: string, b64: string): Promise<string> {
    this.zip.file(name, b64, {base64: true});
    return this.zip.file(name).async("uint8array");
}

您可以利用 "async"-"await" 来处理这种情况。

请参阅此处的示例。

https://stackblitz.com/edit/typescript-async-await-pipeline

您可以将以下登录信息从您的代码段移到单独的文件中:

// Loop through user's local images
    // Edit the converted data to add the image's names to it
    // Convert IMAGE to base64 and add result into zip file
    that.uriToBase64(imageFilePath).then((result) => {
        console.log("image as base64: ", result);
        zip.file(arrayItem2.name, result, {base64: true});
    });

并等待使用 "Promise.all" 解决所有承诺。然后开始将您的 zip 文件写入存储。

@rapropos

回答了问题 here

基本上在获取base64字符串后,在生成ZIP文件时,默认生成的文件类型是blob是错误的原因。将类型更改为 arraybuffer 解决了问题。