I have a for loop that calls a function inside of itself. The function has a callback, however the for loop does not wait for it to finish and continues working.
The for loop actually finishes so quickly that the next action, serving a document that was supposed to be populated inside the for loop, is done before the first function call is completed.
Here is the content of the call I'm actually using, where images is an array holding external URLs to images:
// New jsPDF Document
var doc = new jsPDF();
doc.setFontSize(12);
// For each image we add the image to the document as an image
for (var index = 0; index < images.length; index++) {
// We only add pages after the first one
if (index !== 0) {
doc.addPage();
}
// This puts the URL of the active element at the top of the document
doc.text(35, 25, images[index].path);
// Call to our function, this is the 'skipped' portion
convertImgToDataURLviaCanvas(images[index].path, function(base64Img) {
console.log('An image was processed');
doc.addImage(base64Img, 15, 40, 180, 180);
});
}
doc.save('demo.pdf');
console.log('Document served!');
We get the image URLs from our array, and add everything. The convertImgToDataURLviaCanvas function is here:
// Gets an URL and gives you a Base 64 Data URL
function convertImgToDataURLviaCanvas(url, callback, outputFormat){
var img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function() {
var canvas = document.createElement('CANVAS');
var ctx = canvas.getContext('2d');
var dataURL;
canvas.height = this.height;
canvas.width = this.width;
ctx.drawImage(this, 0, 0);
dataURL = canvas.toDataURL(outputFormat);
callback(dataURL);
canvas = null;
};
img.src = url;
}
In the former examples even the line doc.text(35, 25, images[index].path); does properly write the URLs to the top of the page. Since that is contained in the array and works along the iterator. However, the for loop is completely done before the first image has been added to our document!
With the console.log you would see: 'Document served!' before the first 'An image was processed'. The goal would be for it to be reversed, with every 'An image was processed' being outputted before Document served! appeared.
How can I achieve this functionality?
doc.addPage();to complete before callingconvertImgToDataURLviaCanvas?convertImgToDataURLviaCanvasare called in order, do their callbackdoc.addPage();and then, and only then, let the next loop iteration begin.doc.save()part intoconvertImgToDataURLviaCanvas's callback under for loop?doc.addPage()is callback forconvertImgToDataURLviaCanvas?convertImgToDataURLviaCanvasis called first , thendoc.addPage()is called ? "With the console.log you would see: 'Document served!' before the first 'An image was processed'. "console.log('Document served!');is synchronousdoc.addPage()is inside of the callback.convertImgToDataURLviaCanvas(images[index].path, function(base64Img) { 'This is the callback' });. @alix, that would just try to save as many times as there are files. I suppose the last callback would actually be the proper file, but I don't think that way leads the proper way to a solution.