JavaScript the Fun Part


modern-javascript

await-and-parallelism


In previous post we saw that using multi await does not really seem like running multi-tasks in parallel.

consconsole.log.bind( console );
log( "--- start ---" );

function toUpperCaseLater( string, sync ){
    return new Promise(function( resolve ){
        setTimeout(function(){
            resolve( string.toUpperCase() );
        }, 1000);
    });
}

async function asycn2UpperCase( list ){
    log( `convert all ${list} to uppercase` );
    const how = await toUpperCaseLater( list.shift() );
    log( "list[0]:", how );
    
    const are = await toUpperCaseLater( list.shift() );
    log( "list[1]:", are );
    
    const you = await toUpperCaseLater( list.shift() );
    log( "list[2]:", you );
    
    const today = await toUpperCaseLater( list.shift() );
    log( "list[3]:", today );
}

asycn2UpperCase( [ "how", "are", "you", "today?" ] );
log( "---- end ----" );

It outputs:

--- start ---
convert  all how,are,you,today? to uppercase
---- end ----
list[0]: HOW
list[1]: ARE
list[2]: YOU
list[3]: TODAY?

And we realized that it takes much time:

time node  async-await-2.js 
--- start ---
convert all how,are,you,today? to uppercase
---- end ----
list[0]: HOW
list[1]: ARE
list[2]: YOU
list[3]: TODAY?

real	0m4.150s
user	0m0.129s
sys	0m0.022s

Slow and Fast

The code above was a sample of slow code that has been used to synchronize return value of a promise.

For each await there will be a pause operation that prevent other part of async function to be executed; just like main thread.

You can read about it on MDN Web docs

Now lets change our code to do our tasks faster.

const log = console.log.bind( console );
log( "--- start ---" );

function toUpperCaseLater( string, sync ){
    return new Promise(function( resolve ){
        setTimeout(function(){
            resolve( string.toUpperCase() );
        }, 1000);
    });
}

function asycn2UpperCase( list ){
    log( `convert all ${list} to uppercase` );
    
    list.forEach(async function( item, index ){
        const r = await toUpperCaseLater( item );
        log( `list[${index}]:`, r );
    });
}

asycn2UpperCase( [ "how", "are", "you", "today?" ] );
log( "---- end ----" );

output and time:

time node  async-await-4.js 
--- start ---
convert all how,are,you,today? to uppercase
---- end ----
list[0]: HOW
list[1]: ARE
list[2]: YOU
list[3]: TODAY?

real	0m1.147s
user	0m0.132s
sys	0m0.013s

Using Promise.then

It is not too hard to do the same (= faster) with Promise.then.

const log = console.log.bind( console );
log( "--- start ---" );

function toUpperCaseLater( string, sync ){
    return new Promise(function( resolve ){
        setTimeout(function(){
            resolve( string.toUpperCase() );
        }, 1000);
    });
}

function asycn2UpperCase( list ){
    log( `convert all ${list} to uppercase` );
    
    function sync( index, data ){
        log( `list[${index}]:`, data );
    }

    list.forEach(function( item, index ){
        toUpperCaseLater( item ).then( r => sync( index, r ) );
    });
}

asycn2UpperCase( [ "how", "are", "you", "today?" ] );
log( "---- end ----" );

output and time:

time node  async-await-3.js 
--- start ---
convert all how,are,you,today? to uppercase
---- end ----
list[0]: HOW
list[1]: ARE
list[2]: YOU
list[3]: TODAY?

real	0m1.141s
user	0m0.135s
sys	0m0.009s

Which one? Slow or Fast?

If you wonder which one should be used; it is simple.

If we want to synchronize asynchronous operations that each one depends on previous one, then multi-await is preferable.

In this case:

async function asycn2UpperCase( list ){
    log( `convert all ${list} to uppercase` );
    const how = await toUpperCaseLater( list.shift() );
    log( "list[0]:", how );
    
    const are = await toUpperCaseLater( list.shift() );
    log( "list[1]:", are );
    
    const you = await toUpperCaseLater( list.shift() );
    log( "list[2]:", you );
    
    const today = await toUpperCaseLater( list.shift() );
    log( "list[3]:", today );
}

The function we have toUpperCaseLate does not depend on previous variable (= state) of the program, so why should we wait?

Briefly

Here is a quote from MDN

The purpose of async/await functions is to simplify the behavior of using promises synchronously and to perform some behavior on a group of Promises. Just as Promises are similar to structured callbacks, async/await is similar to combining generators and promises.

So lets see what is generators.


Update: Wed Oct 02 2019 08:05:36 GMT+0330 (Iran Standard Time)