0% found this document useful (0 votes)
19 views69 pages

1 03 Javascript Async Programming

The document provides an overview of asynchronous programming in JavaScript, covering key concepts such as callbacks, functional programming, and database access with SQLite. It explains how JavaScript handles asynchronous operations through the event loop and non-blocking code, emphasizing the importance of callbacks for user actions and I/O operations. Additionally, it introduces the use of SQLite for data persistence in web applications.

Uploaded by

marioestimahackz
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views69 pages

1 03 Javascript Async Programming

The document provides an overview of asynchronous programming in JavaScript, covering key concepts such as callbacks, functional programming, and database access with SQLite. It explains how JavaScript handles asynchronous operations through the event loop and non-blocking code, emphasizing the importance of callbacks for user actions and I/O operations. Additionally, it introduces the use of SQLite for data persistence in web applications.

Uploaded by

marioestimahackz
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 69

Asynchronous

Programming in JS
“The” language of the Web
Fulvio Corno
Luigi De Russis

Applicazioni Web I - Web Applications I - 2023/2024


Outline
• Callbacks
• Functional Programming
• Asynchronous Programming
• Database Access with SQLite
• Promises
• async/await

2
Applicazioni Web I - Web Applications I - 2023/2024
JavaScript: The Definitive Guide, 7th Edition
11.1 Asynchronous Programming with Callbacks

JavaScript – The language of the Web

CALLBACKS

3
Applicazioni Web I - Web Applications I - 2023/2024
https://developer.mozilla.org/en-

Callbacks US/docs/Glossary/Callback_function

• A callback function is a function function logQuote(quote) {


console.log(quote);
passed into another function as }
an argument, which is then
invoked inside the outer function function createQuote(quote,
callback) {
to complete some kind of routine const myQuote = `Like I always
or action. say, '${quote}'`;
callback(myQuote);
– Synchronous
}
– Asynchronous
createQuote("WebApp I rocks!",
logQuote);

4
Applicazioni Web I - Web Applications I - 2023/2024
Synchronous Callbacks
• Used in functional programming
– e.g., providing the sort criteria for array sorting

let numbers = [4, 2, 5, 1, 3]; let numbers = [4, 2, 5, 1, 3];

numbers.sort(function(a, b) { numbers.sort((a, b) => a - b);


return a - b;
});
console.log(numbers);

console.log(numbers);

5
Applicazioni Web I - Web Applications I - 2023/2024
Synchronous Callbacks
• Example: filter according to a criteria
– filter() creates a new array with all elements for which the callback returns true
const market = [
{ name: 'GOOG', var: -3.2 },
{ name: 'AMZN', var: 2.2 },
{ name: 'MSFT', var: -1.8 }
];

const bad = market.filter(stock => stock.var < 0);


// [ { name: 'GOOG', var: -3.2 }, { name: 'MSFT', var: -1.8 } ]

const good = market.filter(stock => stock.var > 0);


// [ { name: 'AMZN', var: 2.2 } ]
6
Applicazioni Web I - Web Applications I - 2023/2024
JavaScript: The Definitive Guide, 7th Edition
Chapter 6. Array
Chapter 7.8 Functional Programming

JavaScript – The language of the Web

FUNCTIONAL PROGRAMMING

7
Applicazioni Web I - Web Applications I - 2023/2024
Functional Programming: A Brief Overview
• A programming paradigm where the developer mostly construct and
structure code using functions
– not JavaScript's main paradigm, but JavaScript is well suited
• More “declarative style” rather than “imperative style” (e.g., for loops)
• Can improve program readability:
new_array = new_array = [] ;
array.filter ( filter_function ) ; for (const el of list)
if ( filter_function(el) )
new_array.push(el) ;

8
Applicazioni Web I - Web Applications I - 2023/2024
Notable Features of the Functional Paradigm
• Functions are first-class citizens
– functions can be used as if they were variables or constants, combined with other
functions and generate new functions in the process, chained with other functions, etc.
• Higher-order functions
– a function that operates on functions, taking one or more functions as arguments and
typically returning a new function
• Function composition
– composing/creating functions to simplify and compress your functions by taking
functions as an argument and return an output
• Call chaining
– returning a result of the same type of the argument, so that multiple functional
operators may be applied consecutively

9
Applicazioni Web I - Web Applications I - 2023/2024
Functional Programming in JavaScript
• JavaScript supports the features of the paradigm “out of the box”
• Functional programming requires avoiding mutability
– i.e., do not change objects in place!
– e.g., if you need to perform a change in an array, return a new array

10
Applicazioni Web I - Web Applications I - 2023/2024
Iterating over Arrays
• Iterators: for ... of, for (..;..;..)
• Iterators: forEach(f)
– Process each element with callback f
• Iterators: every(f), some(f)
Functional style

– Check whether all/some elements in the array satisfy the Boolean callback f
• Iterators that return a new array: map(f), filter(f)
– Construct a new array
• reduce: callback function on all items to progressively compute a result
reduce(callback( accumulator, currentValue[, index[, array]] )[, initialValue])

11
Applicazioni Web I - Web Applications I - 2023/2024
https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

.forEach()
• forEach() invokes your (synchronous) callback function once for each
element of an iterable

const letters = [..."Hello world"] ;


let uppercase = "" ;
letters.forEach(letter => {
uppercase += letter.toUpperCase();
});
console.log(uppercase); // HELLO WORLD

12
Applicazioni Web I - Web Applications I - 2023/2024
https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

.forEach()
• forEach() invokes your (synchronous) callback function once for each
element of an iterable
– The callback may have 3 parameters
• currentValue: The current element being processed in the array.
• index (Optional): The index of currentValue in the array
• array (Optional): The array forEach() was called upon.
– Always returns undefined and is not chainable
– No way to stop or break a forEach() loop other than by throwing an exception
• forEach() does not mutate the array on which it is called
– however, its callback may do so

13
Applicazioni Web I - Web Applications I - 2023/2024
.every()
• every() tests whether all elements in the array pass the test
implemented by the provided function
– Callback: Same 3 arguments as forEach
– It returns a Boolean value (truthy/falsy)
– It executes its callback once for each element present in the array until it finds the
one where the callback returns a falsy value
• If such an element is found, immediately returns false
let a = [1, 2, 3, 4, 5];
a.every(x => x < 10); // => true: all values are < 10
a.every(x => x % 2 === 0); // false: not all even values

14
Applicazioni Web I - Web Applications I - 2023/2024
.some()
• some() tests whether at least one element in the array passes the test
implemented by the provided function
– It returns a Boolean value
– It executes its callback once for each element present in the array until it finds the
one where the callback returns a truthy value
• if such an element is found, immediately returns true

let a = [1, 2, 3, 4, 5];


a.some(x => x%2===0); // => true; a has some even numbers
a.some(isNaN);

15
Applicazioni Web I - Web Applications I - 2023/2024
.map()
• map() passes each element of the array on which it is invoked to the
function you specify
– the callback should return a value
– map() always returns a new array containing the values returned by the callback

const a = [1, 2, 3]; const letters = [..."Hello world"];

const b = a.map(x => x*x); const uppercase = letters.map(letter


=> letter.toUpperCase());

console.log(b); // [1, 4, 9]
console.log(uppercase.join(''));

16
Applicazioni Web I - Web Applications I - 2023/2024
.filter()
• filter() creates a new array with all elements that pass the test
implemented by the provided function
– the callback is a function that returns either true or false
– if no element passes the test, an empty array is returned

const a = [5, 4, 3, 2, 1];

a.filter(x => x < 3); // generates [2, 1], values less than 3

a.filter((element, index) => index%2 == 0); // [5, 3, 1]

17
Applicazioni Web I - Web Applications I - 2023/2024
reduce(

.reduce()
callback(accumulator, currentValue[, index[, array]])
[, initialValue]
)

• reduce() combines the elements of an array, using the specified function,


to produce a single value
– this is a common operation in functional programming and goes by the names “inject”
and “fold”
• reduce takes two arguments:
1. the “reducer function” (callback) that performs the reduction/combination
operation (combine or reduce 2 values into 1)
2. an (optional) initialValue to pass to the function; if not specified, it uses the first
element of the array as initial value (and iteration starts from the next element)

18
Applicazioni Web I - Web Applications I - 2023/2024
.reduce()
const a = [5, 4, 3, 2, 1];
• Callbacks used with reduce() are
different than the ones used with a.reduce( (accumulator, currentValue) =>
forEach() and map() accumulator + currentValue, 0);
// 15; the sum of the values
– the first argument is the accumulated
result of the reduction so far
a.reduce((acc, val) => acc*val, 1);
– on the first call to this function, its first
// 120; the product of the values
argument is the initial value
– on subsequent calls, it is the value
a.reduce((acc, val) => (acc > val) ? acc
returned by the previous invocation of
: val);
the reducer function
// 5; the largest of the values

19
Applicazioni Web I - Web Applications I - 2023/2024
20
Applicazioni Web I - Web Applications I - 2023/2024
JavaScript: The Definitive Guide, 7th Edition
Chapter 11. Asynchronous JavaScript

Mozilla Developer Network


• Learn web development JavaScript » Dynamic client-side
scripting » Asynchronous JavaScript
• Web technology for developers » JavaScript » Concurrency
model and the event loop
• Web technology for developers » JavaScript » JavaScript
Guide » Using Promises

JavaScript – The language of the Web

ASYNCHRONOUS PROGRAMMING

21
Applicazioni Web I - Web Applications I - 2023/2024
Asynchronicity
• JavaScript is single-threaded and inherently synchronous
– i.e., code cannot create threads and run in parallel in the JS engine
• Callbacks are the most fundamental way for writing asynchronous JS
code
• How can they work asynchronously? const deleteAfterTimeout = (task) =>
– e.g., how can setTimeout() or {
other async callbacks work? // do something
}
• Thanks to the Execution Environment // runs after 2 seconds
– e.g., browsers and Node.js setTimeout(deleteAfterTimeout, 2000,
• and the Event Loop task)

22
Applicazioni Web I - Web Applications I - 2023/2024
Non-Blocking Code!
• Asynchronous techniques are very useful, particularly for web development
• For instance: when a web app runs executes an intensive chunk of code
without returning control to the browser, the browser can appear to be frozen
– this is called blocking, and it should be the exception!
• the browser is blocked from continuing to handle user input and perform other tasks until the web
app returns control of the processor
• This may happen outside browsers, as well
– e.g., reading a long file from the disk/network, accessing a database and returning data,
accessing a video stream from a webcam, etc.
• Most of the JS execution environments are, therefore, deeply asynchronous
– with non-blocking primitives
– JavaScript programs are event-driven, typically

23
Applicazioni Web I - Web Applications I - 2023/2024
Asynchronous Callbacks
• The most fundamental way for writing asynchronous JS code
• Great for “simple” things!
const readline = require('readline');
• Handling user actions
– e.g., button click const rl = readline.createInterface({
input: process.stdin,
• Handling I/O operations output: process.stdout
});
– e.g., fetch a document
rl.question('How old are you? ', (answer) => {
• Handling time intervals let description = answer;
– e.g., timers
rl.close();
• Interfacing with databases });

24
Applicazioni Web I - Web Applications I - 2023/2024
Timers
• To delay the execution of a function:
– setTimeout() runs the callback function after a given period of time
– setInterval() runs the callback function periodically

const onesec = setTimeout(()=> { const myFunction = (firstParam,


console.log('hey') ; // after 1s secondParam) => {
}, 1000) ; // do something
}
console.log('hi') ; // runs after 2 seconds
setTimeout(myFunction, 2000,
firstParam, secondParam) ;
Note: timeout value in ms, < 231-1 (about 24 days)
25
Applicazioni Web I - Web Applications I - 2023/2024
Timers
• clearInterval(): for stopping the periodical invocation of
setInterval

const id = setInterval(() => {}, 2000) ;


// «id» is a handle that refers to the timer

clearInterval(id) ;

26
Applicazioni Web I - Web Applications I - 2023/2024
Handling Errors in Callbacks
• No “official” ways, only best practices!
• Typically, the first parameter of the callback function is for storing any
error, while the second one is for the result of the operation
– this is the strategy adopted by Node.js, for instance
fs.readFile('/file.json', (err, data) => {
if (err !== null) {
console.log(err);
return;
}
//no errors, process data
console.log(data);
});

27
Applicazioni Web I - Web Applications I - 2023/2024
Data Persistence

DATABASE ACCESS WITH SQLITE

28
Applicazioni Web I - Web Applications I - 2023/2024
Server-Side Persistence
• A web server should normally store data into a persistent database
• Node supports most databases
– Cassandra, Couchbase, CouchDB, LevelDB, MySQL, MongoDB, Neo4j, Oracle,
PostgreSQL, Redis, SQL Server, SQLite, Elasticsearch
• An easy solution for simple and small-volume applications is SQLite
– in-process on-file relational database

29
Applicazioni Web I - Web Applications I - 2023/2024
SQLite
• Uses the ‘sqlite’ npm module
• Documentation: https://github.com/mapbox/node-sqlite3/wiki

npm install sqlite3

import sqlite from 'sqlite3';


const db = new sqlite.Database('exams.sqlite', // DB filename
(err) => { if (err) throw err; });

...
db.close();

30
Applicazioni Web I - Web Applications I - 2023/2024
SQLite: Queries rows.forEach((row) => {
console.log(row.name);
});

• const sql = "SELECT…";

• db.all(sql, [params], (err, rows) => { } )


– Executes sql and returns all the rows in the callback
– If err is true, some error occurred. Otherwise, rows contains the result
– rows is an array. Each item contains the fields of the result

https://www.sqlitetutorial.net/sqlite-nodejs/
31
Applicazioni Web I - Web Applications I - 2023/2024
SQLite: Queries
rows.forEach((row) => {
console.log(row.name);
});

• db.get(sql, [params], (err, row) => { } )


– Get only the first row of the result (e.g., when the result has 0 or 1 elements:
primary key queries, aggregate functions, …)

• db.each(sql, [params], (err, row) => { } )


– Executes the callback once per each result row (no need to store all of them)

https://www.sqlitetutorial.net/sqlite-nodejs/
32
Applicazioni Web I - Web Applications I - 2023/2024
SQLite: Other Queries
• db.run(sql, [params], function (err) { } )
– For statement that do not return a value
– CREATE TABLE
– INSERT
– UPDATE
– In the callback function
• this.changes == number of affected rows
• this.lastID == number of inserted row ID (for INSERT queries)
• Note: To make this work correctly in the callback, the arrow function syntax cannot be used here

https://www.sqlitetutorial.net/sqlite-nodejs/
33
Applicazioni Web I - Web Applications I - 2023/2024
Parametric Queries
• The SQL string may contain parameter placeholders: ?
• The placeholders are replaced by the values in the [params] array
– in order: one param per each ?

const sql = 'SELECT * FROM course WHERE code=?';


db.get(sql, [code], (err, row) => {

• Always use parametric queries – never string+concatenation nor


`template strings`

34
Applicazioni Web I - Web Applications I - 2023/2024
Example
Table: course Table: score

35
Applicazioni Web I - Web Applications I - 2023/2024
Example
transcript.mjs
import sqlite from 'sqlite3';
const db = new sqlite.Database('transcript.sqlite',
(err) => { if (err) throw err; });

let sql = "SELECT * FROM course LEFT JOIN score ON course.code=score.coursecode" ;


db.all(sql, (err,rows)=>{
if(err) throw err ;
for (let row of rows) {
console.log(row);
}
});

36
Applicazioni Web I - Web Applications I - 2023/2024
Example code: '01TYMOV',
{

name: ' Information systems security ',


import sqlite from 'sqlite3'; CFU: 6,
const db = new sqlite.Database('transcript.sqlite', coursecode: null,
(err) => { if (err) throw err; }); score: null,
laude: null,
datepassed: null
let sql = "SELECT * FROM course LEFT JOIN score ON course.code=score.coursecode" ;
db.all(sql, (err,rows)=>{ }
if(err) throw err ; {
for (let row of rows) { code: '02LSEOV',
console.log(row); name: ' Computer architectures ',
} CFU: 10,
}); coursecode: '02LSEOV',
score: 25,
laude: 0,
datepassed: '2021-02-01'
}

37
Applicazioni Web I - Web Applications I - 2023/2024
But…
import sqlite from 'sqlite3';
const db = new sqlite.Database('transcript.sqlite', (err) => { if (err) throw err; });

let result = [];


let sql = "SELECT * FROM course LEFT JOIN score ON course.code=score.coursecode" ;
db.all(sql, (err,rows)=>{
if(err) throw err ;
for (let row of rows) {
console.log(row);
result.push(row);
}
});
console.log('*************');
for (let row of result) {
console.log(row);
}

38
Applicazioni Web I - Web Applications I - 2023/2024
Queries Are Executed Asynchronously
CREATE TABLE IF NOT EXISTS "numbers" (
"number" INTEGER
);
INSERT INTO "numbers" ("number") VALUES (1);

insert into numbers(number) values(1);


-- Add a new line

select count(*) as tot from numbers;


-- Count how many lines we have

39
Applicazioni Web I - Web Applications I - 2023/2024
Queries Are Executed Asynchronously
import sqlite from 'sqlite3';

const db = new sqlite.Database('data.sqlite',
389
(err) => { if (err) throw err; });
390
for(let i=0; i<100; i++) { 391
db.run('insert into numbers(number) values(1)', 392
(err) => { if (err) throw err; }); 396
396
db.all('select count(*) as tot from numbers', 396
(err, rows) => { 397
if(err) throw err; 398
console.log(rows[0].tot); 399
}) ; 399
400
} 400
db.close(); queries.js …

40
Applicazioni Web I - Web Applications I - 2023/2024
Queries are Executed Asynchronously
import sqlite from 'sqlite3';

const db = new sqlite.Database('data.sqlite',
389
(err) => { if (err) throw err; });
390
for(let i=0; i<100; i++) { 391
db.run('insert into numbers(number) values(1)', 392
(err) => { if (err) throw err; }); 396
396
db.all('select count(*) as tot from numbers', 396
(err, rows) => { 397
if(err) throw err; 398
console.log(rows[0].tot); 399
}) ; 399
400
} 400
db.close(); …

41
Applicazioni Web I - Web Applications I - 2023/2024
Solution?
for(let i=0; i<100; i++) {

db.run('insert into numbers(number) values(1)',


(err) => { if (err) throw err;
else })

db.all('select count(*) as tot from numbers',


(err, rows) => {
if(err) throw err;
console.log(rows[0].tot);

}) ;

42
Applicazioni Web I - Web Applications I - 2023/2024
JavaScript: The Definitive Guide, 7th Edition
Chapter 11. Asynchronous JavaScript

Mozilla Developer Network


• Learn web development JavaScript » Dynamic client-side
scripting » Asynchronous JavaScript
• Web technology for developers » JavaScript » Concurrency
model and the event loop
• Web technology for developers » JavaScript » JavaScript
Guide » Using Promises

JavaScript – The language of the Web

PROMISES

43
Applicazioni Web I - Web Applications I - 2023/2024
Beware: Callback Hell!
• If you want to perform multiple import readline from 'readline';
const rl = readline.createInterface({
asynchronous actions in a row input: process.stdin,
output: process.stdout
using callbacks, you must keep });

passing new functions to handle rl.question('Task description: ', (answer) => {


let description = answer;
the continuation of the
computation after the previous
rl.question('Is the task important? (y/n)', (answer) => {
let important = answer;

action rl.question('Is the task private? (y/n)', (answer) => {


let privateFlag = answer;
– every callback adds a level of nesting
rl.question('Task deadline: ', (answer) => {
– when you have lots of callbacks, the let date = answer;
code starts to be complicated very ...
rl.close();
quickly })
})

})
});

44
Applicazioni Web I - Web Applications I - 2023/2024
Promises
• A core language feature to “simplify” asynchronous programming
– a possible solution to callback hell, too!
– a fundamental building block for “newer” functions (async, ES2017)
• It is an object representing the eventual completion (or failure) of an
asynchronous operation
– i.e., an asynchronous function returns a promise to supply the value at some
point in the future, instead of returning immediately a final value
• Promises standardize a way to handle errors and provide a way for errors
to propagate correctly through a chain of promises

45
Applicazioni Web I - Web Applications I - 2023/2024
Promises
• Promises can be created or consumed
– many Web APIs expose Promises to be consumed!
• When consumed:
– a Promise starts in a pending state
• the caller function continues the execution, while it waits for the Promise to do its own
processing, and give the caller function some “responses”
– then, the caller function waits for it to either return the promise in a fulfilled state
or in a rejected state

46
Applicazioni Web I - Web Applications I - 2023/2024
Creating a Promise
• A Promise object is created using const myPromise =
the new keyword new Promise((resolve, reject) => {
• Its constructor takes an executor
function, as its parameter // do something asynchronous which
• This function takes two functions as eventually call either:
parameters:
– resolve, called when the resolve(someValue); // fulfilled
asynchronous task completes
successfully and returns the results of // or
the task as a value
– reject, called when the task fails and
returns the reason for failure (an error reject("failure reason"); // rejected
object, typically)
});
47
Applicazioni Web I - Web Applications I - 2023/2024
Creating a Promise
function waitPromise(duration) {
// Create and return a new promise
• You can also provide a function return new Promise((resolve, reject) => {
with “promise functionality” // If the argument is invalid,
// reject the promise
• Simply have it return a promise! if (duration < 0) {
reject(new Error('Time travel not yet
implemented'));
} else {
// otherwise, wait asynchronously and then
// resolve the Promise; setTimeout will
// invoke resolve() with no arguments:
// the Promise will fulfill with
// the undefined value
setTimeout(resolve, duration);
}
});
}
48
Applicazioni Web I - Web Applications I - 2023/2024
Consuming a Promise
• When a Promise is fulfilled, the waitPromise().then((result) => {
then() callback is used console.log("Success: ", result);
• If a Promise is rejected, instead, the }).catch((error) => {
catch() callback will handle the console.log("Error: ", error);
error });
• then() and catch() are instance
methods defined by the Promise // if a function returns a Promise...
object waitPromise(1000).then(() => {
– each function registered with then() is console.log("Success!");
invoked only once
}).catch((error) => {
• You can omit catch(), if you are console.log("Error: ", error);
interested in the result, only });

49
Applicazioni Web I - Web Applications I - 2023/2024
Consuming a Promise
• p.then(onFulfilled[, onRejected]);
– Callbacks are executed asynchronously (inserted in the event loop) when the promise
is either fulfilled (success) or rejected (optional)
• p.catch(onRejected);
– Callback is executed asynchronously (inserted in the event loop) when the promise is
rejected
– Short for p.then(null, failureCallback)
• p.finally(onFinally);
– Callback is executed in any case, when the promise is either fulfilled or rejected
– Useful to avoid code duplication in then and catch handlers
• All these methods return Promises, too! ⇒ They can be chained
50
Applicazioni Web I - Web Applications I - 2023/2024
Promise: Create & Consume
const prom = new Promise( prom
(resolve, reject) => { .then((x) => {
... ...use x...
resolve(x); } )
... .catch( (y) => {
reject(y); ...use y...
... } ) ;
}
)

51
Applicazioni Web I - Web Applications I - 2023/2024
Chaining Promises
• One of the most important benefits of getRepoInfo()
Promises .then(repo => getIssue(repo))
• They provide a natural way to express .then(issue => getOwner(issue.ownerId))
a sequence of asynchronous .then(owner => sendEmail(owner.email,
operations as a linear chain of then() 'Some text'))
invocations
.catch(e => {
– without having to nest each operation
within the callback of the previous one // just log the error
• the "callback hell" seen before console.error(e)
– If the error handling code is the same for })
all steps, you can attach catch() to the
end of the chain .finally(_ => logAction());
});
• Important: always return results,
otherwise callbacks won’t get the
result of a previous promise
52
Applicazioni Web I - Web Applications I - 2023/2024
Example: Chaining
• Useful, for instance, with I/O API such as fetch(), which returns a Promise
const status = (response) => {
if (response.status >= 200 && response.status < 300) {
return Promise.resolve(response) // static method to return a fulfilled Promise
}
return Promise.reject(new Error(response.statusText))
}
const json = (response) => response.json()

fetch('/todos.json')
.then(status)
.then(json)
.then((data) => { console.log('Request succeeded with JSON response', data) })
.catch((error) => { console.log('Request failed', error) })

53
Applicazioni Web I - Web Applications I - 2023/2024
Promise.all(promises)
Promises… in Parallel .then(results => console.log(results))
.catch(e => console.error(e));

• What if we want to execute several asynchronous operations in parallel?


• Promise.all()
– takes an array of Promise objects as its input and returns a Promise
– the returned Promise will be rejected if at least one of the input Promises is rejected
– otherwise, it will be fulfilled with an array of the fulfillment values for each of the input
promises
– the input array can contain non-Promise values, too: if an element of the array is not a
Promise, it is simply copied unchanged into the output array
• Promise.race()
– returns a Promise that is fulfilled or rejected when the first of the Promises in the input
array is fulfilled or rejected
– if there are any non-Promise values in the input array, it simply returns the first one

54
Applicazioni Web I - Web Applications I - 2023/2024
JavaScript: The Definitive Guide, 7th Edition
Chapter 11. Asynchronous JavaScript

Mozilla Developer Network


• Learn web development JavaScript » Dynamic client-side
scripting » Asynchronous JavaScript
• Web technology for developers » JavaScript » Concurrency
model and the event loop
• Web technology for developers » JavaScript » JavaScript
Guide » Using Promises

JavaScript – The language of the Web

ASYNC/AWAIT

55
Applicazioni Web I - Web Applications I - 2023/2024
Simplifying Writing With async / await
• ECMAScript 2017 (ES8) introduces two new keywords, async and
await
– write promise-based asynchronous code that looks like synchronous code
• Prepend the async keyword to any function means that it will return a
Promise
• Prepend await when calling an async function (or a function returning
a Promise) makes the calling code stop until the promise is resolved or
rejected
const sampleFunction = async () => {
return 'test'
}
sampleFunction().then(console.log) // This will log 'test'
56
Applicazioni Web I - Web Applications I - 2023/2024
async Functions
• The async function declaration defines an asynchronous function
• Asynchronous functions operate in a separate order than the rest of the
code (via the event loop), returning an implicit Promise as their result
– but the syntax and structure of code using async functions looks like standard
synchronous functions.

async function name([param[, param[, ...param]]]) {


statements
}

https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Statements/async_function
57
Applicazioni Web I - Web Applications I - 2023/2024
await
• The await operator can be used to wait for a Promise. It can only be used inside
an async function
• await blocks the code execution within the async function until the Promise is
resolved
• When resumed, the value of the await expression is that of the fulfilled Promise
• If the Promise is rejected, the await expression throws the rejected value
– If the value of the expression following the await operator is not a Promise, it's converted
to a resolved Promise
returnValue = await expression ;

https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Operators/await
58
Applicazioni Web I - Web Applications I - 2023/2024
Example: async / await
function resolveAfter2Seconds() {
return new Promise(resolve => { Return a
setTimeout(() => { promise
resolve('resolved');
}, 2000);
});
}
async function asyncCall() { async is needed to use await
console.log('calling'); Looks like
const result = await resolveAfter2Seconds(); sequential
console.log(result); code
}
> "calling"
asyncCall(); //... 2 seconds
> "resolved"

59
Applicazioni Web I - Web Applications I - 2023/2024
Example: async / await
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
async function asyncCall() { Implicitly returns a Promise
console.log('calling');
const result = await resolveAfter2Seconds();
return 'end';
}
> "calling"
Can use Promise //... 2 seconds
asyncCall().then(console.log);
methods > "end"

60
Applicazioni Web I - Web Applications I - 2023/2024
Examples… Before and After
const makeRequest = () => { const makeRequest = async () => {
return getAPIData() console.log(await getAPIData());
.then(data => { return "done";
console.log(data); };
return "done";
} let res = makeRequest();
);
}

let res = makeRequest();

61
Applicazioni Web I - Web Applications I - 2023/2024
Examples… Before and After
function getData() {
return getIssue()
.then(issue => getOwner(issue.ownerId))
.then(owner => sendEmail(owner.email, 'Some text'));
}

// assuming that all the 3 functions above return a Promise

async function getData = {


const issue = await getIssue();
const owner = await getOwner(issue.ownerId);
await sendEmail(owner.email, 'Some text');
}

62
Applicazioni Web I - Web Applications I - 2023/2024
Chaining with async/await
• Simpler to read, easier to debug
– debugger would not stop on asynchronous code
const getFirstUserData = async () => {
const response = await fetch('/users.json'); // get users list
const users = await response.json(); // parse JSON
const user = users[0]; // pick first user
const userResponse = await fetch(`/users/${user.name}`); // get user data
const userData = await user.json(); // parse JSON
return userData;
}
getFirstUserData();

63
Applicazioni Web I - Web Applications I - 2023/2024
Promises or async/await? Both!
• If the output of function2 is dependent on the output of function1, use
await.
• If two functions can be run in parallel, create two different async functions
and then run them in parallel Promise.all(promisesArray)
• Instead of creating huge async functions with many await asyncFunction() in
it, it is better to create smaller async functions (not too much blocking code)
• If your code contains blocking code, it is better to make it an async function.
The callers can decide on the level of asynchronicity they want.

https://medium.com/better-programming/should-i-use-promises-or-async-await-126ab5c98789

64
Applicazioni Web I - Web Applications I - 2023/2024
SQLite… revisited
function insertOne() { function printCount() {
return new Promise( (resolve, reject) => { return new Promise( (resolve, reject) => {
db.run('insert into numbers(number) va db.all('select count(*) as tot from nu
lues(1)', (err) => { mbers',
if (err) reject(err); (err, rows) => {
else resolve('Done'); if(err)
}); reject(err);
}) ; else {
} console.log(rows[0].tot);
resolve(rows[0].tot);
}
}) ;
}) ;
}

65
Applicazioni Web I - Web Applications I - 2023/2024
SQLite… revisited
function insertOne() { function printCount() {
return new Promise( (resolve, reject) => { return new Promise( (resolve, reject) => {
db.run('insert into numbers(number) va db.all('select count(*) as tot from nu
lues(1)', (err) => { mbers',
if (err) reject(err); (err, rows) => {
else resolve('Done'); if(err)
}); reject(err);
}) ; else {
async function main() {
} console.log(rows[0].tot);
for(let i=0; i<100; i++) {
resolve(rows[0].tot);
await insertOne();
}
await printCount();
}) ;
}
}) ;
db.close();
}
}

main() ;
66
Applicazioni Web I - Web Applications I - 2023/2024
Beware The Bug!
async function main() {
for(let i=0; i<100; i++) {
await insertOne();
await printCount();
}
db.close();
} async function main() {
for(let i=0; i<100; i++) {
main() ; await insertOne();
await printCount();
}
}

main() ;
db.close();

67
Applicazioni Web I - Web Applications I - 2023/2024
SQLite Libraries: Various Options
• sqlite3: the basic SQLite interface (JS wrapper of the SQLite C library)
• sqlite: This module has the same API as the original sqlite3 library,
except that all its API methods return ES6 Promises.
– internally, it wraps sqlite3; written in TypeScript
• sqlite-async: ES6 Promise-based interface to the sqlite3 module.
• better-sqlite3: Easy-to-use synchronous API (they say it’s faster…)

• … search on https://www.npmjs.com/

68
Applicazioni Web I - Web Applications I - 2023/2024
License
• These slides are distributed under a Creative Commons license “Attribution-NonCommercial-
ShareAlike 4.0 International (CC BY-NC-SA 4.0)”
• You are free to:
– Share — copy and redistribute the material in any medium or format
– Adapt — remix, transform, and build upon the material
– The licensor cannot revoke these freedoms as long as you follow the license terms.
• Under the following terms:
– Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were
made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or
your use.
– NonCommercial — You may not use the material for commercial purposes.
– ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions
under the same license as the original.
– No additional restrictions — You may not apply legal terms or technological measures that legally restrict
others from doing anything the license permits.
• https://creativecommons.org/licenses/by-nc-sa/4.0/

69
Applicazioni Web I - Web Applications I - 2023/2024

You might also like