Search code examples
javascriptecmascript-6promisees6-promise

Misunderstanding of Promise returns in a chain


I have a function that resamples a canvas image to a second canvas. As far as I understand it, by using then, it's using promises and is helping me obtain the delayed return, rather than getting something undefined if the return came too early.

function resample_sizeo(canvas, width, height) {

    // Initialize
    var resizer = sizeo();

    var canvasResampled = document.createElement('canvas');
    canvasResampled.width = width;
    canvasResampled.height = height;
    // Function using two canvas' in the form of: resize(from, to)
    return resizer.resize(canvas, canvasResampled)
    // Function that converts resampled canvas to a data blob
    .then(result => resizer.toBlob(result, 'image/jpeg', 95))
    // End with a blob to return
    .then(blob => blob);
}

I wish to chain together n amount of calls to resample_sizeo and run them sequentially. This is a popular request I see, and I also see that it's addressed well with await/async but I can't use these yet for reasons I won't go into here.

I got pretty close with using some scripts like Promise-Waterfall but found my attempts to satisfy it's array of promise-returning functions were doubling my code and that - perhaps - I was going about this a long way if I already had a function that returned a promise. Maybe I was overcomplicating something simple and I had 90% of the work done. So I tried returning to my friend then. Surely if my function as already returning a promise, I could chain some calls to the function together?

resample_sizeo(sourceCanvas, widthsRequired[0], heightsRequired[0])
.then(function(result) { // (**)
    console.log(result);
    resampledImageBlobs[0] = result;
    resample_sizeo(sourceCanvas, widthsRequired[1], heightsRequired[1])
}).then(function(result) { // (***)
    resampledImageBlobs[1] = result;
    resample_sizeo(sourceCanvas, widthsRequired[2], heightsRequired[2])
}).then(function(result) {
    resampledImageBlobs[2] = result;
    resample_sizeo(sourceCanvas, widthsRequired[3], heightsRequired[3])
}).then(function(result) {
    resampledImageBlobs[3] = result;
    console.log("All done", resampledImageBlobs);
    uploadImageBlobSet(resampledImageBlobs, 'replace');
});

This didn't work. resampledImageBlobs shows that it's [blob,undefined,undefined,undefined] at the end, so it's not waiting for each function to finish before reaching the end. I've overlooked something. If I check the result of any of these calls individually, they return a blob. But they're not chaining sequentially and waiting in turn.


Solution

  • You need to return the promise from resample_sizeo. Otherwise your next call to .then(...) will run immediately, and the result argument will be the usual return value of a function, which is undefined:

    resample_sizeo(sourceCanvas, widthsRequired[0], heightsRequired[0])
    .then(function(result) { // (**)
        console.log(result);
        resampledImageBlobs[0] = result;
        return resample_sizeo(sourceCanvas, widthsRequired[1], heightsRequired[1])
    }).then(function(result) { // (***)
        resampledImageBlobs[1] = result;
        return resample_sizeo(sourceCanvas, widthsRequired[2], heightsRequired[2])
    }).then(function(result) {
        resampledImageBlobs[2] = result;
        return resample_sizeo(sourceCanvas, widthsRequired[3], heightsRequired[3])
    }).then(function(result) {
        resampledImageBlobs[3] = result;
        console.log("All done", resampledImageBlobs);
        uploadImageBlobSet(resampledImageBlobs, 'replace');
    });