EcmaScript async-await

Declaration

1
2
3
4
5
6
7
8
9
10
11
12
// classic declaration 
async function functionName (arguments) {
// Do something asynchronous
}
// arrow declaration
const functionNameAWithrrows = async (arguments) => {
// Do something asynchronous
}

// they always return promises
const promise = functionName(arguments);
console.log(promise); // Promise

Promises return something in the future:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
getSomethingWithPromise()
.then(data => {/* do something with data */})
.catch(err => {/* handle the error */});

// promise return
const promise = new Promise((resolve, reject) => {
// Note: only 1 param allowed
return resolve(42);
})

// Parameter passed resolve would be the arguments passed into then.
promise.then(number => console.log(number)); // 42

// promise reject
const promise = new Promise((resolve, reject) => {
// Note: only 1 param allowed
return reject('💩');
})

// Parameter passed into reject would be the arguments passed into catch.
promise.catch(err => console.log(err)); // 💩

// full example
const ChellWantsCake = cakeType => {
return new Promise((resolve, reject) => {
setTimeout(()=> {
if (cakeType == 'Portal cake') {
resolve('You got a cake!');
} else {
reject('The cake is lie');
}
}, 1000)//timeout
})
}

Await

It lets you wait for the promise to resolve, once it finishes it returns the parameter passed into the then call.

1
2
3
4
5
6
const test = async _ => {
const one = await getOne() {
console.log(one); // 1
}
}
test();

Return await

There’s no need to await before returning a promise. You can return the promise directly.

(If you return await something, you resolve the original promise first. Then, you create a new promise from the resolved value. return await effectively does nothing. No need for the extra step).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Don’t need to do this 
const test = async _ => {
return await getOne();
}
test()
.then(value => {
console.log(value) // 1
});

// Do this instead
const test = async _ => {
return getOne();
}
test()
.then(value => {
console.log(value); // 1
});

If you don’t need await, you don’t need to use an async function. The example above can be rewritten as follows:

1
2
3
4
5
6
7
8
// Do this instead
const test = _ => {
return getOne();
}
test()
.then(value => {
console.log(value); // 1
})

Handling errors

Rejects can be handled with catch

1
2
3
4
5
6
7
8
const getOne = async (success = true) => { 
if (success){
return 1;
throw new Error(‘💩’);
}
}
getOne(false)
.catch(error => console.log(error)); // 💩

You can use use a try/catch calls

1
2
3
4
5
6
7
8
const test = async _ => {
try {
const one = await getOne(false);
} catch (error) {
console.log(error); // 💩
}
}
test();

If you have multiple await keywords, error handling can become ugly…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// You do not need to this
const test = async _ => {
try {
const one = await getOne(false);
} catch (error) {
console.log(error); // 💩
}
try {
const two = await getTwo(false);
} catch (error) {
console.log(error); // 💩
}
try {
const three = await getThree(false);
} catch (error) {
console.log(error); // 💩
}
}
test();

// Do this instead
const test = async _ => {
const one = await getOne(false);
const two = await getTwo(false);
const three = await getThree(false);
}
// get a single error, just one
test()
.catch(error => console.log(error));

Multiple awaits

await blocks JavaScript from executing the next line of code until a promise resolves -> slow down execution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// delaying a function a number of milliecons (ms)
const sleep = ms => {
return new Promise(resolve => setTimeout(resolve, ms));
}

console.log(‘Now’);
// using Sleep, we delay 1 second
sleep(1000)
.then(v => { console.log(‘After one second’) });
// console logs ‘Now’ immediately. One second later, it logs ‘After one second’

const getOne = _ => {
// sleep 1 second, then return "1"
return sleep(1000).then(v => 1);
}

If you await getOne(), you’ll see that it takes one second before getOne resolves.

1
2
3
4
5
6
7
8
const test = async _ => {
// console logs ‘Now’ immediately
console.log(‘Now’);
const one = await getOne();
// after one second, console logs 1
console.log(one);
}
test();

Let’s suppose we add 3 promises

  • You may wait for three seconds before all three promises get resolved

    1
    2
    3
    4
    5
    6
    7
    8
    9
    const getOne = _ => {
    return sleep(1000).then(v => 1);
    };
    const getTwo = _ => {
    return sleep(1000).then(v => 2);
    };
    const getThree = _ => {
    return sleep(1000).then(v => 3);
    };
  • Or you may search all simultaneously

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    const test = async _ => {
    // console shows ‘Now’ immediately
    console.log(‘Now’);
    const one = await getOne();
    console.log(one);
    const two = await getTwo();
    console.log(two);
    const three = await getThree
    // 'three' and 'done' appear at the same time
    console.log(three);
    console.log(‘Done’);
    };
    test();
  • All these promises may be fetched with Promise.all

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // create the three promises before this
    const test = async _ => {
    //add all three promises into an array
    const promises = [getOne(), getTwo(), getThree()];
    console.log(‘Now’);
    // await the array of promises with Promise.all
    const [one, two, three] = await Promise.all(promises);
    console.log(one);
    console.log(two);
    console.log(three);
    console.log(‘Done’);
    }
    test();
    // console shows ‘Now’ immediately
    // after one second, console shows 1, 2, 3, and ‘Done’

Async series parallel and waterfall

  • async.series: waiting for each preceding function to finish before starting next

  • async.parallel: launch them all functions simultaneously

  • async.waterfall: like series, but passed using an array

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    async.parallel({
    func1: function(cb) {
    cb(null, { foo: 'bar' });
    },
    func2: function(cb) {
    async.waterfall([
    function(cb2) {
    cb2(null, 'a');
    },
    function(prev, cb2) {
    cb2(null, 'b');
    }
    ], function(err, result) {
    cb(err, result);
    });
    }
    }, function(err, results) {
    callback(err, results);
    });