Async await function not ending in the order that it should Javascript

481 views Asked by At

Why is the function convertToPng that I have stated to await for until completion, specifically until the imgOnLoad is entered and the PDF is created, is still being executed simultaneously?

Actual Results

enter image description here

  1. "Convert to png function has ended"
  2. "Proceeding after convert to png"
  3. "Saving PDF INTO COMPUTER"
  4. "imgOnLoad event entered"
  5. "ATTACHING IMAGE 1"

Expected Result

  1. "imgOnLoad event entered"
  2. "ATTACHING IMAGE 1"
  3. "Convert to png function has ended"
  4. "Proceeding after convert to png"
  5. "Saving PDF INTO COMPUTER"

Simplified Code

for (let i = 0; i< selected_views.length; i++) {
    $('.loading-text').html("Exporting...");
    $('.loading-count').html((i + 1) + "/" + selected_views.length);
    let node = document.getElementsByClassName('view-container view-grid-' + view_id[1])[0];
    const data = await convertToPng(doc,node,doc_width,doc_height,doc_wh_ratio);
    console.log("Proceeding after convert to png");
}
$('.loading-text').html("Loading...");
$("#loading").hide();
console.log("SAVING PDF INTO COMPUTER"); 
doc.save(dashboard_name + '_' + client_name + '.pdf');


async function convertToPng(doc,page,doc_width,doc_height,doc_wh_ratio) {
            // window.html2canvas = html2canvas;
            // Go to next page
            doc.addPage();
            let chartNodes = page.childNodes;
            for(let i =0; i < chartNodes.length; i++){
                console.log(chartNodes[i]);
                console.log(chartNodes[i].firstChild.firstChild);
                if(chartNodes[i].firstChild.firstChild.tagName == 'TABLE'){
                    (doc.autoTable({ html: chartNodes[i].firstChild.firstChild }));
                }
                else{
                    let options = { "cacheBust":true }
                    let dataUrl = await domtoimage.toPng(page,options);
                    console.log('~~~~~~~~~');
                    console.log(dataUrl);
                    console.log('~~~~~~~~~');
                    img.src = dataUrl;
                    let img = new Image();
                    img.onload = function() {
                        console.log("imgOnLoad event entered");
                        img_wh_ratio = img.width / img.height;
                        if (img_wh_ratio > doc_wh_ratio) {
                            console.log("ATTACHING IMAGE 1");
                            // Add dashboard image to pdf with margins
                            doc.addImage(dataUrl, 'PNG', 2, 2, doc_width - 4, 0); // Set width as limiting dimension
                        }
                        else {
                            console.log("ATTACHING IMAGE 2");
                            // Get margins to centralize horizontally
                            let new_width = img.width * doc_height / img.height;
                            let total_margin = doc_width - new_width;
                            let side_margin = total_margin / 2;
                            // Add dashboard image to pdf with margins
                            doc.addImage(dataUrl, 'PNG', side_margin + 2, 2, 0, doc_height - 4); // Set height as limiting dimension
                        }
                    }
                }
            }
            console.log("Convert to png function has ended");
        }
1

There are 1 answers

3
obscure On BEST ANSWER

That is because the onload event inside your convertToPng() function is happening asynchronous. By itself it does not return a promise so you need to put the loading procedure in another function which returns a promise alongside the image.

This way you can use the await keyword and await the actual image result - img = await loadImage(dataUrl);.

For example:

function loadImage(path) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.src = path;
    img.onload = () => {
      resolve(img);
    }
    img.onerror = e => {
      reject(e);
    }
  });
}
async function convertToPng(doc, page, doc_width, doc_height, doc_wh_ratio) {
  // window.html2canvas = html2canvas;
  // Go to next page
  doc.addPage();
  let chartNodes = page.childNodes;
  for (let i = 0; i < chartNodes.length; i++) {
    console.log(chartNodes[i]);
    console.log(chartNodes[i].firstChild.firstChild);
    if (chartNodes[i].firstChild.firstChild.tagName == 'TABLE') {
      (doc.autoTable({
        html: chartNodes[i].firstChild.firstChild
      }));
    } else {
      let options = {
        "cacheBust": true
      }
      let dataUrl = await domtoimage.toPng(page, options);
      console.log('~~~~~~~~~');
      console.log(dataUrl);
      console.log('~~~~~~~~~');
      let img = await loadImage(dataUrl);
      console.log("imgOnLoad event entered");
      img_wh_ratio = img.width / img.height;
      if (img_wh_ratio > doc_wh_ratio) {
        console.log("ATTACHING IMAGE 1");
        // Add dashboard image to pdf with margins
        doc.addImage(dataUrl, 'PNG', 2, 2, doc_width - 4, 0); // Set width as limiting dimension
      } else {
        console.log("ATTACHING IMAGE 2");
        // Get margins to centralize horizontally
        let new_width = img.width * doc_height / img.height;
        let total_margin = doc_width - new_width;
        let side_margin = total_margin / 2;
        // Add dashboard image to pdf with margins
        doc.addImage(dataUrl, 'PNG', side_margin + 2, 2, 0, doc_height - 4); // Set height as limiting dimension
      }
    }
  }
  console.log("Convert to png function has ended");
}