关于异步函数的问题以及我应该如何正确 运行 它同步
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
解决了问题。
我有以下算法:
// 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 文件中的内容。考虑到这一点,我寻找了一些相关的问题,这让我想到了这个
这是我尝试做的:
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
解决了问题。