# Async Await
Read chapters Microtasks (opens new window), Async/Await (opens new window) and Event Loop (opens new window) (and specially section Macrotasks and Microtasks (opens new window)) of the https://javascript.info (opens new window) book and make a report using the GitHub Classroom assigned repo. Solve the exercises.
# Exercise 1: MicroTask and MacroTask Queues
Answer this question before running the program.
What is the output of this program?
setTimeout(function () { //C1
console.log('macrotask 1');
}, 0);
Promise.resolve().then(function () { // P1
console.log('microtask 1');
setTimeout(function () { // C2
console.log('macrotask 2');
Promise.resolve().then( // P3
() => console.log('Nested microtask 3')
)
}, 0);
}).then(function () { // P2
console.log('microtask 2');
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Explain the changes in the stack, the running environment, the macrotask queue and the microtask queue. Make pictures of the way the callbacks and handlers go and leave the queues. Take screenshots of them and upload them to the assignment repo
- Code at:
campus-virtual/2021/sytws2021/apuntes/tema2-async/event-loop/exercises/promises/microtask-queue/promise-job-queue-2.js
# Exercise 2: MicroTask and MacroTask Queues
The following example is taken from a stackoverflow question
Don't look at the debate yet. Also, try to answer this question before running the code.
What is the output of this program?
// See https://stackoverflow.com/questions/51793906/settimeout-promise-resolve-macrotask-vs-microtask
for (let i = 0; i < 2; i++) {
setTimeout(() => { // M1
console.log("Timeout ", i);
Promise.resolve().then(() => { // P1
console.log("Promise 1 ", i);
}).then(() => { // P2
console.log("Promise 2 ", i);
});
})
}
2
3
4
5
6
7
8
9
10
11
Explain the changes in the stack, the running environment, the macrotask queue and the microtask queue. Make pictures of the way the callbacks and handlers go and leave the queues. Take screenshots of them and upload them to the assignment repo
# Exercise 3: Rewrite a fetch
using async/await instead of promises
Rewrite this example code from the Javascript.info book, section Bigger example: fetch (opens new window) using async/await
instead of .then/catch
:
function loadJson(url) {
return fetch(url)
.then(response => {
if (response.status == 200) {
return response.json();
} else {
throw new Error(response.status);
}
});
}
loadJson('no-such-user.json').catch(console.log); // Error: 404
2
3
4
5
6
7
8
9
10
11
12
# Exercise 4: Rewrite "rethrow" with async/await
Below you can find another exercise from the book javascript.info Rewrite "rethrow" with async/await (opens new window)).
The code keep asking for a GitHub user until a valid login is given.
Rewrite it using async/await
instead of .then/catch
and get rid of the recursion in favour of a loop in demoGithubUser
: with async/await
.
class HttpError extends Error {
constructor(response) {
super(`${response.status} for ${response.url}`);
this.name = 'HttpError';
this.response = response;
}
}
function loadJson(url) {
return fetch(url)
.then(response => {
if (response.status == 200) {
return response.json();
} else {
throw new HttpError(response);
}
});
}
// Ask for a user name until github returns a valid user
function demoGithubUser() {
let name = prompt("Enter a name?", "iliakan");
return loadJson(`https://api.github.com/users/${name}`)
.then(user => {
alert(`Full name: ${user.name}.`);
return user;
})
.catch(err => {
if (err instanceof HttpError && err.response.status == 404) {
alert("No such user, please reenter.");
return demoGithubUser();
} else {
throw err;
}
});
}
demoGithubUser();
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
35
36
37
38
39
- See Section Custom errors, extending Error (opens new window). It is worth to read the full chapter Error Handling (opens new window)
- See The Error Class at MDN: The constructor (opens new window)
# Exercise 5: Call async from non-async
Here is another exercise from the JavaScript.Info book (opens new window). As the book says, it is a task that solves a quite common for developers new to async/await.
We have a "regular" function called f
. How can you call the async
function wait()
and use its result inside of f
?
Give at least two solutions.
async function wait() {
await new Promise(resolve => setTimeout(resolve, 1000));
return 10;
}
function f() {
// ...what should you write here?
// we need to call async wait() and wait to get 10
// remember, we can't use "await"
}
2
3
4
5
6
7
8
9
10
11
# Exercise 6: Rendering
Explain the differences in behavior between these two progress bar programs:
counting-progress-bar-macro.html
and counting-progress-bar.html
:
async-await-solution git:(main) ✗ cat queue-microtask/counting-progress-bar-macro.html
The counting-progress-bar-macro.html
uses setTimeout
to split the heavy task into pieces and give the browser a chance to paint changes:
<div id="progress"></div>
<script>
// If we split the heavy task into pieces using setTimeout,
// then changes are painted out in-between them.
let chunkSize = 1e5; // 1e5;
let i = 0;
function count() {
// do a piece of the heavy job (*)
do {
i++;
progress.innerHTML = i;
} while (i % chunkSize != 0);
if (i < 1e7) { // call recursively if incomplete
setTimeout(count);
}
}
count();
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
and
➜ async-await-solution git:(main) ✗ cat queue-microtask/counting-progress-bar.html
The counting-progress-bar.html
uses queueMicrotask
to attempt to split the heavy task into pieces and give the browser a chance to paint changes but it does not work as expected:
<!doctype html>
<body>
<div id="progress"></div>
<script>
/*
Here’s an example with “counting progress bar”, but queueMicrotask is used instead of setTimeout.
You can see that it renders at the very end.
*/
let i = 0;
function count() {
// do a piece of the heavy job (*)
do {
i++;
progress.innerHTML = i;
} while (i % 1e3 != 0);
//console.log(i);
if (i < 1e6) {
queueMicrotask(count);
}
}
count();
</script>
</body>
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
What is the explanation?
# Exercise 7: Yet another microtask-macrotask exercise
Task from https://javascript.info/event-loop#what-will-be-the-output-of-this-code (opens new window)
What will be the output of this code?
console.log(1);
setTimeout(() => console.log(2));
Promise.resolve().then(() => console.log(3));
Promise.resolve().then(() => setTimeout(() => console.log(4)));
Promise.resolve().then(() => console.log(5));
setTimeout(() => console.log(6));
console.log(7);
2
3
4
5
6
7
8
9
10
11
12
13
# Exercise 8: The GitHub REST API
The GitHub API doc for the end-point to get the public info for an user is here GitHub API REST Docs: Get a User (opens new window). Here are several examples of how to get the info:
gh api /users/crguezl --jq '.name'
or with curl
✗ curl \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/users/crguezl | jq '.name'
2
3
or using the @octokit/core
module:
cat the-github-api/octokit--example.js
const { Octokit } = require('@octokit/core')
const octokit = new Octokit({
auth: process.env.GITHUB_TOKEN
})
async function getUsername (name) {
return await octokit.request('GET /users/{username}', {
username: name
})
}
getUsername('crguezl').then(r => console.log('NAME: ', r.data.name))
async function getRepos (name) {
return await octokit.graphql(
`query ($login: String!) {
organization(login: $login) {
repositories(privacy: PRIVATE, first: 100) {
totalCount
}
}
}`,
{ login: name }
)
}
getRepos('ULL-MII-SYTWS-2223').then(r =>
console.log('REPOS: ', r.organization.repositories.totalCount)
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
Reproduzca los requests de ejemplo hechos en esta sección.
# References
- JavaScript.Info book: Bigger example: fetch (opens new window)
- Custom errors, extending Error (opens new window)
- For the solutions:
campus-virtual/2021/sytws2021/apuntes/tema2-async/event-loop/exercises/promises/microtask-queue
campus-virtual/2021/sytws2021/apuntes/tema2-async/event-loop/exercises/promises/async-await