Skip to content

Instantly share code, notes, and snippets.

@dylancwood

dylancwood/post.md

Created Aug 16, 2015
Embed
What would you like to do?
Promise tips

I spent a little time in a Promise rabbit-hole today, and thought I'd share two rules-of-thumb that I came up with to avoid such holes in the future. This came from writing Mocha tests, but it applies to lots of code:

Example:

describe('Some Async Test', () => {
    var myPromise;
    before('Do some async setup', () => {
        myPromise = doSomethingAsync();
        return myPromise;
    });

    it('Should do something else async', () => {
        return myPromise.then( () => {
            doSomethingElseAsync() //no return!!
                .then((response) => {
                    //more processing
                });
        });
   });

});

The only thing critically wrong with this is that the Promise returned by doSomethingElseAsync is not returned. Thus, mocha will think that the test has completed (since the test function returns a Promise that resolves to undefined instead of a Promise that resolves to another Promise).

To avoid this, we can do two things:

Try to keep promise-chains as flat as possible.

Always try to keep promise chains one-dimensional. Nesting .then inside of functions is a sure-fire way to get mixed up. Here is the above example with just this rule applied to it:

describe('Some Async Test', () => {
    var myPromise;
    before('Do some async setup', () => {
        myPromise = doSomethingAsync();
        return myPromise;
    });

    it('Should do something else async', () => {
        return myPromise
            .then(doSomethingElseAsync)
            .then((response) => {
                //more processing
            });
   });

});

Use Mocha's built-in flow control

Remember that if a mocha it, before, beforeEach, etc... is passed an expression that returns a promise (as these are), then mocha will wait for that promise to resolve before continuing. Consequently, we don't need to chain onto myPromise in the tests at all.

Here's what this looks like applying these rules of thumb:

describe('Some Async Test', () => {
    before('Do some async setup', () => {
        return doSomethingAsync();
    });

    it('Should do something else async', () => {
        return doSomethingElseAsync()
                .then((response) => {
                    //more processing
                });
        });
   });

});

Bonus tip:

tip: You can use lodash's _.partial and _.partialRight function if you need to pass extra arguments to the function that you are putting in .then:

function handleBothArgs(arg1, arg2) {
    //...
};

function run() {
    var arg2 = 'foo';

    return getArg1Async()
        .then(_.partialRight(handleBothArgs, arg2)); //will call handleBothArgs(arg1, arg2) :-)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.