英文:
JavaScript - Wait for a promise to finish before next loop iteration
问题
您正在尝试创建一个Web应用程序,允许用户上传PDF文件,使用水平和垂直选择器截取其中的片段,然后一旦他们有一个选定的片段列表,他们可以按照他们想要的任何顺序重新排列它们,然后应用程序会生成一个新的PDF文件,其中包含这些片段按照所选的顺序排列。
问题在于,该应用程序经常会将片段按照错误的顺序放入新的PDF文件中。
我认为问题出在代码中读取每个页面并粘贴片段的承诺在应用程序进入循环的下一次迭代之前尚未完成。我尝试将for循环放入异步函数中,并在承诺开始时使用await,但似乎没有任何作用。
您可以采取什么措施来修复这个问题?
var currentWriteHeight = 0; // 用于确定新PDF中的页面上有多少内容需要创建新页面
// 打开要截取的PDF文件
const fileName = '../static/upload/' + fileData['fileName'];
pdfjsLib.getDocument(fileName).then((pdfRead) => {
// 创建新的PDF文件
var hSize = fileData['maxPageWidth'];
var vSize = fileData['maxPageHeight'];
const pdfWrite = new jsPDF({ unit: 'px', format: [hSize, vSize] });
// 这是指定新文件中片段顺序的数组
const positionArray = JSON.parse(fileData['positionArray']);
for (const x in positionArray) {
// 获取当前片段的数据
const currentClip = clipData[positionArray[x]];
const currentPage = currentClip['pageNumber'];
// 将当前页面放入画布
pdfRead.getPage(currentPage).then((page) => {
const canvas1 = document.createElement('canvas');
const ctx = canvas1.getContext("2d", { willReadFrequently: true });
const viewport = page.getViewport(1);
canvas1.width = viewport.width;
canvas1.height = viewport.height;
page.render({
canvasContext: ctx,
viewport: viewport
}).then((rendered) => {
// 将页面裁剪到clip数据中指定的尺寸
const minY = currentClip['minY'] * (page.view[3] - page.view[1]) / 600;
const maxY = currentClip['maxY'] * (page.view[3] - page.view[1]) / 600;
let minX = 0;
let maxX = (page.view[2] - page.view[0]);
if (currentClip['minX'] != null && currentClip['maxX'] != null) {
minX = currentClip['minX'] * (page.view[3] - page.view[1]) / 600;
maxX = currentClip['maxX'] * (page.view[3] - page.view[1]) / 600;
}
const clipImgData = ctx.getImageData(minX, minY, (maxX - minX), (maxY - minY));
canvas1.width = (maxX - minX);
canvas1.height = (maxY - minY);
ctx.putImageData(clipImgData, 0, 0);
// 如果当前图像将总高度超出页面高度,创建新页面
if ((currentWriteHeight + canvas1.height) > vSize) {
pdfWrite.addPage({ format: [hSize, vSize] });
currentWriteHeight = 0;
}
// 将图像添加到页面
pdfWrite.addImage(canvas1, 'PNG', 0, currentWriteHeight, canvas1.width, canvas1.height);
currentWriteHeight += canvas1.height;
// 如果这是最后一个图像,显示新的PDF文件
if (x == positionArray.length - 1) {
window.open(pdfWrite.output('bloburl'), '_blank');
}
});
canvas1.remove();
});
}
});
示例数据:
fileData =
fileName: "48 Moonrunner.pdf"
maxPageHeight: 509.28
maxPageWidth: 315.75359999999995
positionArray: "[0, 19, 20, 2, 3, 22, 21, 14, 15, 16, 17, 11, 9, 4, 5, 8, 12, 13, 10, 6, 18, 7, 1]"
clipData =
0: { pageNumber: 1, minY: 0, maxY: 600, minX: 413, maxX: 773 }
1: { pageNumber: 19, minY: 49, maxY: 296, minX: 372, maxX: 721 }
2: { pageNumber: 20, minY: 49, maxY: 360, minX: 0, maxX: 372 }
3: { pageNumber: 27, minY: 438, maxY: 555, minX: 372, maxX: 721 }
4: { pageNumber: 32, minY: 310, maxY: 367, minX: 364, maxX: 715 }
5: { pageNumber: 33, minY: 48, maxY: 107, minX: 0, maxX: 364 }
6: { pageNumber: 36, minY: 324, maxY: 544, minX: 0, maxX: 364 }
7: { pageNumber: 39, minY: 296, maxY: 558, minX: 364, maxX: 721 }
8: { pageNumber: 43, minY: 286, maxY: 417, minX: 0, maxX: 364 }
9: { pageNumber: 59, minY: 59, maxY: 283, minX: 364, maxX: 715 }
10: { pageNumber: 83, minY: 312, maxY: 545, minX: 364, maxX: 715 }
11: { pageNumber: 87, minY: 222, maxY: 552, minX: 364, maxX: 721 }
12: { pageNumber: 91, minY: 0, maxY: 600, minX: 0, maxX: 364 }
13: { pageNumber: 91, minY: 51, maxY: 340, minX: 364, maxX: 715 }
14: { pageNumber: 96, minY: 158, maxY: 382, minX: 0, maxX: 364 }
15: { pageNumber: 104, minY: 53, maxY: 273, minX: 364, maxX: 715 }
16: { pageNumber: 107, minY: 0, maxY: 600, minX: 0, maxX:
<details>
<summary>英文:</summary>
I am trying to make a web application that allows the user to upload a pdf file, take clips of it with a horizontal and vertical selector, then once they have a list of the clips selected, they can rearrange them in whatever order they want, and the application then makes a new pdf file with those clips in that order.
The problem is, the application ends up frequently putting the clips into the new pdf file out of order.
I figure the issue with the code is the promise that happens to read each page and paste the clips is not finished before the application goes to the next iteration in the loop. I have tried putting the for loop inside an async function, and beginning the promise with await, but nothing seems to work.
What can I do to fix this?
The code:
var currentWriteHeight = 0; //used to determine how much is on a page in the new pdf before a new one must be created
// open the pdf file to be clipped
const fileName = '../static/upload/' + fileData['fileName'];
pdfjsLib.getDocument(fileName).then((pdfRead) => {
// create new pdf file
var hSize = fileData['maxPageWidth'];
var vSize = fileData['maxPageHeight'];
const pdfWrite = new jsPDF({unit: 'px',format: [hSize, vSize]});
// this is the array that states what order the clips are in in the new file
const positionArray = JSON.parse(fileData['positionArray']);
for (const x in positionArray) {
//get data for current clip
const currentClip = clipData[positionArray[x]];
const currentPage = currentClip['pageNumber'];
// put current page in a canvas
pdfRead.getPage(currentPage).then((page) => {
const canvas1 = document.createElement('canvas');
const ctx = canvas1.getContext("2d", { willReadFrequently: true });
const viewport = page.getViewport(1);
canvas1.width = viewport.width;
canvas1.height = viewport.height;
page.render({
canvasContext: ctx,
viewport: viewport
}).then((rendered) => {
// crop page down to dimensions specified in clip data
const minY = currentClip['minY'] * (page.view[3] - page.view[1]) / 600;
const maxY = currentClip['maxY'] * (page.view[3] - page.view[1]) / 600;
let minX = 0;
let maxX = (page.view[2] - page.view[0]);
if (currentClip['minX'] != null && currentClip['maxX'] != null) {
minX = currentClip['minX'] * (page.view[3] - page.view[1]) / 600;
maxX = currentClip['maxX'] * (page.view[3] - page.view[1]) / 600;
}
const clipImgData = ctx.getImageData(minX, minY, (maxX - minX), (maxY - minY));
canvas1.width = (maxX - minX);
canvas1.height = (maxY - minY);
ctx.putImageData(clipImgData, 0, 0);
// if current image would put total over page height, make new page
if ((currentWriteHeight + canvas1.height) > vSize) {
pdfWrite.addPage({format: [hSize, vSize]});
currentWriteHeight = 0;
}
// add image to page
pdfWrite.addImage(canvas1, 'PNG', 0, currentWriteHeight, canvas1.width, canvas1.height);
currentWriteHeight += canvas1.height;
// if this is the last image, show the new pdf file
if (x == positionArray.length - 1) {
window.open(pdfWrite.output('bloburl'), '_blank');
}
});
canvas1.remove();
});
}
});
Sample data used:
fileData =
fileName: "48 Moonrunner.pdf"
maxPageHeight: 509.28
maxPageWidth: 315.75359999999995
positionArray: "[0, 19, 20, 2, 3, 22, 21, 14, 15, 16, 17, 11, 9, 4, 5, 8, 12, 13, 10, 6, 18, 7, 1]"
clipData =
0: {pageNumber: 1, minY: 0, maxY: 600, minX: 413, maxX: 773}
1: {pageNumber: 19, minY: 49, maxY: 296, minX: 372, maxX: 721}
2: {pageNumber: 20, minY: 49, maxY: 360, minX: 0, maxX: 372}
3: {pageNumber: 27, minY: 438, maxY: 555, minX: 372, maxX: 721}
4: {pageNumber: 32, minY: 310, maxY: 367, minX: 364, maxX: 715}
5: {pageNumber: 33, minY: 48, maxY: 107, minX: 0, maxX: 364}
6: {pageNumber: 36, minY: 324, maxY: 544, minX: 0, maxX: 364}
7: {pageNumber: 39, minY: 296, maxY: 558, minX: 364, maxX: 721}
8: {pageNumber: 43, minY: 286, maxY: 417, minX: 0, maxX: 364}
9: {pageNumber: 59, minY: 59, maxY: 283, minX: 364, maxX: 715}
10: {pageNumber: 83, minY: 312, maxY: 545, minX: 364, maxX: 715}
11: {pageNumber: 87, minY: 222, maxY: 552, minX: 364, maxX: 721}
12: {pageNumber: 91, minY: 0, maxY: 600, minX: 0, maxX: 364}
13: {pageNumber: 91, minY: 51, maxY: 340, minX: 364, maxX: 715}
14: {pageNumber: 96, minY: 158, maxY: 382, minX: 0, maxX: 364}
15: {pageNumber: 104, minY: 53, maxY: 273, minX: 364, maxX: 715}
16: {pageNumber: 107, minY: 0, maxY: 600, minX: 0, maxX: 364}
17: {pageNumber: 107, minY: 53, maxY: 444, minX: 364, maxX: 721}
18: {pageNumber: 112, minY: 331, maxY: 552, minX: 0, maxX: 364}
19: {pageNumber: 120, minY: 0, maxY: 600, minX: 0, maxX: 364}
20: {pageNumber: 120, minY: 54, maxY: 446, minX: 364, maxX: 721}
21: {pageNumber: 123, minY: 284, maxY: 550, minX: 0, maxX: 364}
22: {pageNumber: 127, minY: 56, maxY: 324, minX: 364, maxX: 715}
</details>
# 答案1
**得分**: 1
将您的代码重写以使用 `async`/`await`。这不仅可以修复您原始的问题,还具有以下几个好处:
- 减少缩进量
- 减少复杂性
- 不再需要检测循环的最后一次迭代 - 打开窗口的代码仅在循环外部执行
```javascript
var currentWriteHeight = 0; // 用于确定在新的 PDF 中一页上有多少内容之前必须创建新的页面
// 打开要裁剪的 PDF 文件
const fileName = '../static/upload/' + fileData['fileName'];
const pdfRead = await pdfjsLib.getDocument(fileName);
// 创建新的 PDF 文件
var hSize = fileData['maxPageWidth'];
var vSize = fileData['maxPageHeight'];
const pdfWrite = new jsPDF({ unit: 'px', format: [hSize, vSize] });
// 这是指定新文件中剪辑顺序的数组
const positionArray = JSON.parse(fileData['positionArray']);
for (const x in positionArray) {
// 获取当前剪辑的数据
const currentClip = clipData[positionArray[x]];
const currentPage = currentClip['pageNumber'];
// 将当前页放入画布中
const page = await pdfRead.getPage(currentPage);
const canvas1 = document.createElement('canvas');
const ctx = canvas1.getContext("2d", { willReadFrequently: true });
const viewport = page.getViewport(1);
canvas1.width = viewport.width;
canvas1.height = viewport.height;
const rendered = await page.render({
canvasContext: ctx,
viewport: viewport
});
// 裁剪页面至剪辑数据中指定的尺寸
const minY = currentClip['minY'] * (page.view[3] - page.view[1]) / 600;
const maxY = currentClip['maxY'] * (page.view[3] - page.view[1]) / 600;
let minX = 0;
let maxX = (page.view[2] - page.view[0]);
if (currentClip['minX'] != null && currentClip['maxX'] != null) {
minX = currentClip['minX'] * (page.view[3] - page.view[1]) / 600;
maxX = currentClip['maxX'] * (page.view[3] - page.view[1]) / 600;
}
const clipImgData = ctx.getImageData(minX, minY, (maxX - minX), (maxY - minY));
canvas1.width = (maxX - minX);
canvas1.height = (maxY - minY);
ctx.putImageData(clipImgData, 0, 0);
// 如果当前图像将总高度超出页面高度,创建新页面
if ((currentWriteHeight + canvas1.height) > vSize) {
pdfWrite.addPage({ format: [hSize, vSize] });
currentWriteHeight = 0;
}
// 将图像添加到页面
pdfWrite.addImage(canvas1, 'PNG', 0, currentWriteHeight, canvas1.width, canvas1.height);
currentWriteHeight += canvas1.height;
canvas1.remove();
}
window.open(pdfWrite.output('bloburl'), '_blank');
英文:
Rewrite your code to use async
/await
. This has a few benefits on top of fixing your original issue:
- reduces the amount of indentation
- reduces the complexity
- stops you having to detect the last iteration of your loop - the open window code just goes outside the loop
var currentWriteHeight = 0; //used to determine how much is on a page in the new pdf before a new one must be created
// open the pdf file to be clipped
const fileName = '../static/upload/' + fileData['fileName'];
const pdfRead = await pdfjsLib.getDocument(fileName);
// create new pdf file
var hSize = fileData['maxPageWidth'];
var vSize = fileData['maxPageHeight'];
const pdfWrite = new jsPDF({unit: 'px',format: [hSize, vSize]});
// this is the array that states what order the clips are in in the new file
const positionArray = JSON.parse(fileData['positionArray']);
for (const x in positionArray) {
//get data for current clip
const currentClip = clipData[positionArray[x]];
const currentPage = currentClip['pageNumber'];
// put current page in a canvas
const page = await pdfRead.getPage(currentPage);
const canvas1 = document.createElement('canvas');
const ctx = canvas1.getContext("2d", { willReadFrequently: true });
const viewport = page.getViewport(1);
canvas1.width = viewport.width;
canvas1.height = viewport.height;
const rendered = await page.render({
canvasContext: ctx,
viewport: viewport
});
// crop page down to dimensions specified in clip data
const minY = currentClip['minY'] * (page.view[3] - page.view[1]) / 600;
const maxY = currentClip['maxY'] * (page.view[3] - page.view[1]) / 600;
let minX = 0;
let maxX = (page.view[2] - page.view[0]);
if (currentClip['minX'] != null && currentClip['maxX'] != null) {
minX = currentClip['minX'] * (page.view[3] - page.view[1]) / 600;
maxX = currentClip['maxX'] * (page.view[3] - page.view[1]) / 600;
}
const clipImgData = ctx.getImageData(minX, minY, (maxX - minX), (maxY - minY));
canvas1.width = (maxX - minX);
canvas1.height = (maxY - minY);
ctx.putImageData(clipImgData, 0, 0);
// if current image would put total over page height, make new page
if ((currentWriteHeight + canvas1.height) > vSize) {
pdfWrite.addPage({format: [hSize, vSize]});
currentWriteHeight = 0;
}
// add image to page
pdfWrite.addImage(canvas1, 'PNG', 0, currentWriteHeight, canvas1.width, canvas1.height);
currentWriteHeight += canvas1.height;
canvas1.remove();
}
window.open(pdfWrite.output('bloburl'), '_blank');
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论