DEV Community

Jordan Hansen
Jordan Hansen

Posted on • Originally published at javascriptwebscrapingguy.com on

Jordan promises – async/await vs .then

As I’ve stated in a lot of other posts, I’m a big fan of async/await. I think it’s a pretty clean way to manage code your synchronous and asynchronous code.

Async/Await awesomeness

I want to compare some of the bad that can be avoided with async/await.


// Yucky then usage
async function getThePizza() {
    functionGettingFromMongo('someArguments').then((someData) => {

        // We want to use this data so we need to know that this promise completed
        doSomeWorkWithAPromise().then((moreData) => {
            const somethingCool = someData + moreData;

            insertToMongoNow(somethingCool).then((response) => {
                console.log('success!', response);
            }).catch((e) => {
                console.log('some error happened', e);
            });
        });

    });
}

So this is a function where we are entering callback hell. While .then() isn’t a callback function, codewise it reads the exact same. It’s a bunch of nested functions that get deeper and deeper and make code less and less readable.


// So good.
async function getThePizza() {
    const someData = await functionGettingFromMongo('someArguments');
    const moreData = await doSomeWorkWithAPromise();

    const somethingCool = someData + moreData;
    try {
        const response = await insertToMongoNow(somethingCool );
        console.log('success!', response);
    }
    catch(e) {
        console.log('some error happened', e);
    }

}

It’s a lot more readable. At the least it’s not getting more and more indented. I had been using async/await exclusively since I discovered it so much so that I started thinking of .then() as bad and kind of forgot that the beauty of programming is that almost everything is situational.

When .then() isn’t so bad

When I’m trying to scrape a lot of pages at once I don’t want to be blocked. I don’t use await but instead push the promises into an array and use Promise.all. That will ensure that I know when everything completes so I can close my db connection or puppeteer browser. Like this:

async function getThePizza() {

    const promises: any[] = [];
    for (let url of lotsAndLotsOfUrls) {
        promises.push(functionForHandlingTheUrl(url));
    }

    await Promise.all(promises);
    await closeMyDbConnectionOrPuppeteerOrSomething();
}

This works fine. Except for when I want to do something with the specific url after functionForHandlingTheUrl finishes with it. Now what? Using await looks like this:

async function getThePizza() {

    for (let url of lotsAndLotsOfUrls) {
        const something = await functionForHandlingTheUrl(url);
        await dbWorkOrSomething(something);
    }

    await closeMyDbConnectionOrPuppeteerOrSomething();
}

Very readable but much slower. I’m no longer taking advantage of any concurrency around I/O threads. So what’s the better alternative? This worked GREAT:

async function getThePizza() {

    const promises: any[] = [];
    for (let url of lotsAndLotsOfUrls) {
        promises.push(functionForHandlingTheUrl(url).then(something => {
            // This parts only happens when functionForHandlingTheUrl completes and doesn't block the rest
            return dbWorkOrSomething(something);
        }));

    }

    await Promise.all(promises);
    await closeMyDbConnectionOrPuppeteerOrSomething();
}

Using .then() here makes it so I have one nested function, it’s true, but we are able to do stuff when only that specific iteration is ready. It doesn’t block the rest of the looping so I am still lightning fast. And I am happy.

Small PS. A lot of my featured images have been from Unsplash.com. It’s a REALLY great resource. Today’s is from Connor Jolley. Thanks Connor!

The post Jordan promises – async/await vs .then appeared first on JavaScript Web Scraping Guy.

Top comments (3)

Collapse
 
johncarroll profile image
John Carroll • Edited

Async/await is obviously better (in most cases) then .then() style promise handling, but your first example of "Yucky then usage" seems unnecessarily bad. Unless I am missing something, there is no apparent reason for the code to be implemented that way (other than inexperience).

You could argue that one of the benefits of async/await is that it's harder for an inexperienced programmer to use the syntax improperly, but you haven't made that argument.

That same example can be implemented much more cleanly/realistically (while still using .then())

function getThePizza() {
  let someData;

  return functionGettingFromMongo('someArguments')
    .then(data => {
      someData = data;
      return doSomeWorkWithAPromise();
    })
    .then(data => insertToMongoNow(someData + data))
    .then(response => { console.log('success!', response) })
    .catch(e => { console.error('some error happened', e) })
}

While .then() isn’t a callback function, codewise it reads the exact same.

False. It only reads that way because of a poor implementation.

Collapse
 
gypsydave5 profile image
David Wickes

Your example of 'bad' promises would look nicer with a Promise.all (imho), and would incidentally run the two asynchronous calls concurrently.

Collapse
 
adam_cyclones profile image
Adam Crockett 🌀

Async your post is good await the punchline then laugh. Sorry couldn't resist!