0

I'm trying to load a bunch of resources async using promises with Jimp.js. The loading code is a disaster trying to chain it all, and I need a cleaner solution.

What I came up with was below. This obviously doesn't do anything, because it's junk code, but I need to know if there was a failure loading any of the resources, and I need to know when they completed.

function doSomething(asdf) {
  return new Promise((resolve, reject) => {
    //console.log("It is done.");
    // Succeed half of the time.
    var x = Math.random();    
    if (x > .5) {
      resolve(["SUCCESS",asdf,x])
    } else {
      reject(["Failure",asdf,x])
    }
  });
}



func();

function func() {
    //Imagine a is actually an image loaded by doSomething
    var a=null;  doSomething("1").then(function (data) {a = data;},
            (err) => {throw new err;});
    //Imagine b is a font resource.
    var b=null;  doSomething("2").then(function (data) {b = data;},
            (err) => {throw new err;});

    Promise.all([a, b]).then(function() {
            console.log(a);
            console.log(b);
            //Then here I expect everything to be correct, and continue on with the next function.
    }, 
    (err) => {console.log('Oops:' + err);}).
     catch( (err) => {console.log('Oops:' + err);});
}

For some reason, this never outputs "Oops".

Here is a fail output:

[ 'SUCCESS', '1', 0.756461151774289 ] null

What am I missing here?

Update

I took part of an answer I received and changed it so that it behaves exactly as I wanted:

function func() {
    var a=doSomething("1").then(function (data) {a = data;});
    var b=doSomething("2").then(function (data) {b = data;});

    Promise.all([a, b]).then(function() {
            console.log(a);
            console.log(b);
    }, 
    (err) => {console.log('Reject:' + err);});
}

Update

Here is the actual code I'm using that's working great now:

LoadResources() {
    var ps = [];
    console.log("Loading now");

    ps.push(jimp.read(this.ipath+"c4box.png").then(function (image) {obj.imBox = image;}));
    ps.push(jimp.read(this.ipath+"red.png").then(function (image) {obj.imRed = image;}));
    ps.push(jimp.read(this.ipath+"green.png").then(function (image) {obj.imGreen = image;}));
    ps.push(jimp.read(this.ipath+"top.png").then(function (image) {obj.imTop = image;}));
    ps.push(jimp.read(this.ipath+"bot.png").then(function (image) {obj.imBot = image;}));
    ps.push(jimp.loadFont(jimp.FONT_SANS_32_WHITE).then(function (font) {obj.imFont = font;}));

    Promise.all(ps).then( () => {
            obj.loaded = true;
            obj.imBg = new jimp(512, 576, function (err, image) { });
            console.log("Actually loaded now.");                       
            obj.StartGame();
    });
    console.log("Loading commands complete");            
    }

3 Answers 3

2

You cannot use those a and b variables for the images. (See here for the values that would be passed into Promise.all). You need to use variables for the promise objects that doSomething() returns. The images will only be available inside the then callback - Promise.all creates a promise that fulfills with an array of the results:

function func() {
    // aPromise is a promise for an image loaded by doSomething
    var aPromise = doSomething("1");
    // bPromise is a promise for a font resource.
    var bPromise = doSomething("2");

    Promise.all([aPromise, bPromise]).then(function([a, b]) {
//                                                  ^^^^^^
        console.log(a);
        console.log(b);
        // Then here I expect everything to be correct, and continue on with the next function.
    }, (err) => {
        console.log('Oops:' + err);})
    });
}
Sign up to request clarification or add additional context in comments.

9 Comments

Alternatively, if the data needs to be formatted, or only specific parts need to be extracted, you can keep the .then() on the .doSomething() call, like so: aPromise = doSomething("1").then(function (data) { return data.subData; }. The important piece is the return statement inside the .then(), so it can continue to be chained
Thanks, I changed it to var a = doSomething()... and it's perfect. I will update the question for the future.
@CharlesW No, don't use .then(function (data) {a = data;});
The reason that I did that was that a and b are class variables for storing images for later use. This is a persistent project in node.js. Could you further explain why I should not?
@CharlesW Those variables are useless because you never know when you can already use them or not (if the promise was not fulfilled (yet)). Instead, store the promise object itself on your class instance.
|
1
  Promise.all([a, b])

Cause a and b are null as you set them to null. Therefore Promise.all won't wait at all, it will resolve one tick afterwards, and as a and b get resolved / rejected very fast, that might has happened before and a / b gets set before it reaches

 console.log(a)

which will log the right results sometimes, but thats based on chance.

Comments

1

Promise.all returns a promise and this promise contains the result of the previous promises

Promise.all([ doSomething('1'), doSomething('2')])
  .then(results => {
    // results is an array which contains the result of the previous promises
    const [a, b] = results
  }).catch(err => console.log('Oops:' + err))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.