Home > Mobile >  What would a specific example of a simple async/await function be expressed as Promises?
What would a specific example of a simple async/await function be expressed as Promises?

Time:05-09

I'm trying to understand the relationship between async/await and Promises in TypeScript and have gotten myself a but too confused, I think.

Im particular, I'm trying to understand how the async/await version of an example function, downloadFileAA, defined below maps to an implementation that uses Promises instead. What is going in behind the scenes with Promises? Obviously neither of my Promise versions are satisfactory or entirely capture what's going on in the async/await version (downloadFilePromise never reports success or failure, and downloadFilePromise2 requires some weird redundancy: result.then() in the argument to resolve to pass type checking), but I'm not certain why.

What would a Promise-based version of downloadFileAA look like? Is there a reason to prefer it (or not) over the async/await version?

import * as FileSystem from 'expo-file-system'

const callback = ( downloadProgress ) => {
    const progress = downloadProgress.totalBytesWritten / downloadProgress.totalBytesExpectedToWrite
    console.log(
        `${Number( progress )
            .toLocaleString( undefined, { style: 'percent', minimumFractionDigits: 0 } )
            .padStart( 5, ' ' )} of ${downloadProgress.totalBytesExpectedToWrite} bytes`
    )
}

const downloadResumable = FileSystem.createDownloadResumable(
    'http://...',
    FileSystem.documentDirectory   'somebigfile',
    {},
    callback
)

const downloadFileAA = async () => {
    try {
        console.log( 'Starting download (with async/await)... ' )
        const result = await downloadResumable.downloadAsync()
        console.log( result ? `Finished downloading to ${result.uri}` : 'Undefined result?'  )
    } catch ( e ) {
        console.error( `Failed download: ${e.message}` )
    }
}

const downloadFilePromise = () => {
        console.log( 'Starting download (with Promise)... ' )
        new Promise<FileSystem.FileSystemDownloadResult>(  ( resolve, reject ) =>
            downloadResumable.downloadAsync()
         )
            .then( ( result ) => console.log( `Finished downloading to ${result.uri}` ) )
            .catch( ( reason ) => console.error( `Failed download: ${reason}` ) )
}

const downloadFilePromise2 = () => {
        console.log( 'Starting download (with Promise Two)... ' )
        new Promise<FileSystem.FileSystemDownloadResult>(  ( resolve, reject ) => {
            const result = downloadResumable.downloadAsync()
            result  ? resolve( result.then() ) : reject( result )
        } )
            .then( ( result ) => console.log( `Finished downloading to ${result.uri}` ) )
            .catch( ( reason ) => console.error( `Failed download: ${reason}` ) )
}

CodePudding user response:

Assuming that downloadAsync returns a Promise and that console.log doesn't throw, this

const downloadFileAA = async () => {
    try {
        console.log( 'Starting download (with async/await)... ' )
        const result = await downloadResumable.downloadAsync()
        console.log( result ? `Finished downloading to ${result.uri}` : 'Undefined result?'  )
    } catch ( e ) {
        console.error( `Failed download: ${e.message}` )
    }
}

is equivalent to

const downloadFileAA = () => {
    console.log('Starting download (with async/await)... ')
    return downloadResumable.downloadAsync()
        .then((result) => {
            console.log(result ? `Finished downloading to ${result.uri}` : 'Undefined result?')
        })
        .catch((e) => {
            console.error(`Failed download: ${e.message}`);
        });
};

What await does is it replaces .then. It doesn't replace Promises - both .then and await require a Promise (to be used sensibly, at least).

Your downloadFilePromise function is broken because it constructs a Promise that, by definition, never resolves - you must call the resolve or reject argument in order for the constructed Promise to resolve. But since it looks like downloadAsync already returns a Promise, constructing another Promise to surround it doesn't make any sense - just use the Promise you have instead of making a new one.

Is there a reason to prefer it (or not) over the async/await version?

It's purely a stylistic choice. IMO await shines best when there are multiple values that need to be waited for (serially), but otherwise either work just fine (as long as they're implemented properly, of course).

  • Related