Peter
Peter

Reputation: 14098

Calling promise in another promise, conditionally

This is basically my code, using q:

let d = Q.defer();
let result = {
    name: 'peter'
};

d.resolve(result);
return d.promise;

However, I now need to perform a step based on a certain condition. This step is calling another object that also returns a promise. So I'm having nested promises, if that's the correct term.

Something like this:

let d = Q.defer();
let result = {
    name: 'peter'
};

if (someParameter) {
    otherService.getValue() // Let's say it returns 'mary'
        .then((res) => {
            result.name = res;
        });
}

d.resolve(result);
return d.promise;

This doesn't work however (the name property is still 'peter'). Probably due to the fact that my inner promise is resolved at a later moment?

I've also tried this, but it doesn't work if I call the otherService which returns a promise. It does work if I just set the value:

let d = Q.defer();
let result = {
    name: 'peter'
};

d.resolve(result);
return d.promise
    .then((data) => {
        if (someParameter) {
            // Works
            data.name = 'john';

            // Doesn't work
            otherService.getValue()
                .then((res) => {
                    data.name = res;
                });
        }

        return data;
    });

Here the name will be 'john', not 'mary'.

Clearly I'm misunderstanding promises, but I can't wrap my head around it.

Upvotes: 1

Views: 3310

Answers (2)

Bergi
Bergi

Reputation: 664246

Using deferreds is deprecated. If at all, you should use the Q.Promise constructor, but you don't even need that. Just use the Q function to create a promise that is fulfilled with your value.

Now you can (and should) simplify your code to

let d = someParameter ? otherService.getValue() : Q('peter');
return d.then(res => ({
    name: res
}));

Upvotes: 2

Davin Tryon
Davin Tryon

Reputation: 67296

Control flow with Promises is...fun?

Anyway, you are nearly there, you can embed a Promise in a Promise as well as chain them. However, if you are embedding them, you must return the embedded Promise chain:

let d = Q.defer();
let result = {
    name: 'peter'
};

d.resolve(result);
return d.promise
    .then((data) => {
        if (someParameter) {

            // Should work now that we return the Promise
            return otherService.getValue()
                .then((res) => {
                    data.name = res;
                    // And we have to return the data here as well
                    return data;
                });
        }

        return data;
    });

Promise resolve can take a value or another Promise and it will handle the flow. So, when we return inside a then, the value we are returning can be another Promise or just a value. The machinery will take care of unwrapping for us.

Upvotes: 1

Related Questions