Adam Kettani
Adam Kettani

Reputation: 93

Async function inside Promises

Here is my situation:

fetchData(foo).then(result => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(result + bar);
        }, 0)
    });
}).then(result => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve( result + woo);
        }, 0)
    });
}).then(result => {
    setTimeout(() => {
        doSomething(result);
    }, 0)
});

Where each setTimeout is a different async operation using the callback pattern.

It is really painfull to wrap each function inside a promise, I feel like the code should look more like this:

fetchData(foo).then(result => {
    setTimeout(() => {
        return result + bar;
    }, 0)
}).then(result => {
    setTimeout(() => {
        return result + woo;
    }, 0)
}).then(result => {
    setTimeout(() => {
        doSomething(result);
    }, 0)
});

Obviously this doesn't work.

Am I using Promises right? Do I really have to wrap all existing async function in promises?

EDIT:

Actually I realize my example was not totally reprensentative of my situation, I did not make it clear that the setTimeout in my example is meant to reprensent en async operation. This situation is more representative of my situation:

fetchData(foo).then(result => {
    return new Promise((resolve, reject) => {
        asyncOperation(result, operationResult => {
            resolve(operationResult);
        }, 0)
    });
}).then(result => {
    return new Promise((resolve, reject) => {
        otherAsyncOperation(result, otherAsyncResult => {
            resolve( otherAsyncResult);
        }, 0)
    });
}).then(result => {
        doSomething(result);
});

Upvotes: 1

Views: 1871

Answers (2)

Bergi
Bergi

Reputation: 665334

Am I using Promises right? Do I really have to wrap all existing async function in promises?

Yes. Yes.

I feel like the code should look more like this

No, it shouldn't. It rather should look like this:

function promiseOperation(result) {
    return new Promise((resolve, reject) => {
        asyncOperation(result, resolve, 0)
    });
}
function otherPromiseOperation(result) {
    return new Promise((resolve, reject) => {
        otherAsyncOperation(result, resolve, 0)
    });
}

fetchData(foo).then(promiseOperation).then(otherPromiseOperation).then(doSomething);

It is really painfull to wrap each function inside a promise

Well, don't repeatedly write it out every time. You can abstract this wrapping into a function!

function promisify(fn) {
    return value => new Promise(resolve => {
        fn(value, resolve, 0)
    });
}
const promiseOperation = promisify(asyncOperation);
const otherPromiseOperation = promisify(otherAsyncOperation);
fetchData(foo).then(promiseOperation).then(otherPromiseOperation).then(doSomething);

Notice that most promise libraries come with a such a promisification function included, so your whole code reduces to these three lines.

Upvotes: 3

Andrea
Andrea

Reputation: 3440

You are using promise right. Just a small note on the first snippet of code: you are not returning a promise from the last then() callback:

...
}).then(result => {
    setTimeout(() => {
        doSomething(result);
    }, 0)
});

This is correct if you need simply to do an async operation without returning to the caller of fetchData the value of the last async operation. If you need to return this value, you need to convert to promise this operation too:

fetchData(foo).then(result => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(result + bar);
        }, 0)
    });
}).then(result => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(result + woo);
        }, 0)
    });
}).then(result => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(doSomething(result));
        }, 0)
    });  
});

Here I suppose doSomething is a sync function returning a value.

Said so, if you want to reduce the noise of create the promise to wrap setTimeout every time, you can create a utility function setTimeoutWithPromise:

function setTimeoutWithPromise(operation, millisec) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(operation());
        }, millisec)
    });
}

And clean your code:

fetchData(foo)
    .then(result => setTimeoutWithPromise(() => result + bar, 0))
    .then(result => setTimeoutWithPromise(() => result + woo, 0))
    .then(result => setTimeoutWithPromise(() => doSomething(result), 0));

Upvotes: 0

Related Questions