Andreas
Andreas

Reputation: 20

JS Promise wait for nested asynchronous function

I'm having an issue getting 2 asynchronous operations properly timed so the outer function waits for the inner function to finish before continuing. The solution I'm trying to implement is based on an existing solution which uses ES2015, so I can't use await and have to work with Promises.

The solution is split in multiple classes, which for an easy overview I call Main, Invoker and Inner. So the Main class uses an instance of the Invoker to asynchronously execute a command from the Inner class and should then wait for the response, which works but it doesn't wait for the asynchronous Image.onload() from the setSize() of the Inner class.

class Inner extends Component{
    setSize(size){
        const newImage = { url: null, imageName: canvasImage.imageName};
        
        ... some stuff...
        const tempImage = new Image();
        tempImage.src = canvas.toDataURL();
        tempImage.onload = function(){
        
            ... some stuff...
            const tempCanvas = document.createElement("canvas");
            const tempCtx = tempCanvas.getContext("2d");
            tempCtx.drawImage(image, x, y, xa, ya);

            newImage.url = tempCanvas.toDataURL();
        }
        return Promise.resolve(newImage);
    }
}


class Main{
    resize(size){
        imageData = this.execute(commandName,'setSize', size);
        
        imageData.then(image => {
            ... do stuff with image data...
        });
    }
    execute(commandName, ...args) {
        return this._invoker.execute(commandName, ...args);
    }
}

class Invoker{
    execute(...args) {

        let [command] = args;
        if (isString(command)) {
          command = commandFactory.create(...args);
        }

        return this._invokeExecution(command).then((value) => {
          this.clearRedoStack();

          return value;
        });
    }
}

I already tried to move the "return Promise.resolve(newImage) in the setSize Function inside the onload function, but then I'm getting an error in the invoker, because of the missing resolve. Any ideas?

Upvotes: 0

Views: 52

Answers (2)

oieduardorabelo
oieduardorabelo

Reputation: 2985

since the setSize function is using a callback based syntax with onload, you need to wait until the onload function is called by the browser,

you can return a promise from setSize and handle onload for resolve and onerror for reject, something like:

setSize(size){
    return new Promise((res, rej) => {
      const newImage = { url: null, imageName: canvasImage.imageName};
      
      ... some stuff...
      const tempImage = new Image();
      tempImage.src = canvas.toDataURL();
      tempImage.onload = function(){
      
          ... some stuff...
          const tempCanvas = document.createElement("canvas");
          const tempCtx = tempCanvas.getContext("2d");
          tempCtx.drawImage(image, x, y, xa, ya);

          newImage.url = tempCanvas.toDataURL();
          res(newImage);
      }
      tempImage.onerror = function(error) {
        rej(error)
      }
    })
}

Upvotes: 3

Clem
Clem

Reputation: 2312

You need to return a promise and resolve it in the onload.

setSize () {
  return new Promise((resolve, reject) => {
    ...
    tempImage.onload = function () {
      ...
      resolve(newimage)
    }
  })
}

Upvotes: 3

Related Questions