Share
Asynchronous JavaScript - there and back again
The links from the presentation are available here:
maciejtreder.github.io/asynchronous-javascript/
https://www.twilio.com/blog/asynchronous-javascript-understanding-callbacks
https://www.twilio.com/blog/asynchronous-javascript-organize-callbacks-readability-reusability
https://www.twilio.com/blog/asynchronous-javascript-introduction-promises
https://www.twilio.com/blog/asynchronous-javascript-advanced-promises-chaining-collections-nodejs
https://www.twilio.com/blog/asynchronous-javascript-refactor-callbacks-promises-node-js
https://www.twilio.com/blog/asynchronous-javascript-reactivex-rxjs-observables-nodejs
https://www.twilio.com/blog/async-js-rxjs-observables-rest-api-nodejs
https://www.twilio.com/blog/real-time-event-notifications-using-node-js-rxjs-observables-twilio-programmable-sms
https://www.twilio.com/blog/asynchronous-javascript-introducing-async-and-await
https://www.twilio.com/blog/asynchronous-javascript-using-promises-rest-apis-nodejs
Maciej Treder
Transcript
108 slides
-
function saySomethingNice():void { console.log(`Nice to meet you.`); } function greet(name:
string): void { console.log(`Hello ${name}!`); saySomethingNice(); } greet(`John`); Hello John! Nice to meet you. -
function saySomethingNice():void { console.log(`Nice to meet you.`); } function greet(name:
string): void { setTimeout(() => console.log(`Hello ${name}!`, 0)); saySomethingNice(); } greet(`John`); Nice to meet you. Hello John! -
Those are not part of JavaScript • setTimeout • setInterval
• fetch • DOM • window -
Event Loop stack callbacks queue function saySthNice():void { } function
greet(name: string): void { saySthNice(); } greet(`John`); setTimeout(() => console.log(`Hello ${name}!`, 0)); saySthNice(); console.log(`Nice to meet you.`); -
Event Loop stack callbacks queue main() function saySthNice():void { }
function greet(name: string): void { saySthNice(); } greet(`John`); setTimeout(() => console.log(`Hello ${name}!`, 0)); saySthNice(); console.log(`Nice to meet you.`); -
Event Loop greet() stack callbacks queue main() function saySthNice():void {
} function greet(name: string): void { saySthNice(); } greet(`John`); setTimeout(() => console.log(`Hello ${name}!`, 0)); saySthNice(); console.log(`Nice to meet you.`); -
Event Loop greet() stack callbacks queue main() function saySthNice():void {
} function greet(name: string): void { saySthNice(); } greet(`John`); setTimeout() setTimeout(() => console.log(`Hello ${name}!`, 0)); saySthNice(); console.log(`Nice to meet you.`); -
Event Loop greet() stack setTimeout API callbacks queue main() function
saySthNice():void { } function greet(name: string): void { saySthNice(); } greet(`John`); setTimeout() setTimeout(() => console.log(`Hello ${name}!`, 0)); saySthNice(); console.log(`Nice to meet you.`); -
Event Loop greet() stack setTimeout API callbacks queue main() function
saySthNice():void { } function greet(name: string): void { saySthNice(); } greet(`John`); setTimeout() setTimeout(() => console.log(`Hello ${name}!`, 0)); saySthNice(); console.log(`Nice to meet you.`); -
Event Loop greet() stack setTimeout API callbacks queue main() function
saySthNice():void { } function greet(name: string): void { saySthNice(); } greet(`John`); setTimeout() console.log() setTimeout(() => console.log(`Hello ${name}!`, 0)); saySthNice(); console.log(`Nice to meet you.`); -
Event Loop greet() stack setTimeout API callbacks queue main() function
saySthNice():void { } function greet(name: string): void { saySthNice(); } greet(`John`); setTimeout() console.log() setTimeout(() => console.log(`Hello ${name}!`, 0)); saySthNice(); console.log(`Nice to meet you.`); -
Event Loop greet() stack setTimeout API callbacks queue main() function
saySthNice():void { } function greet(name: string): void { saySthNice(); } greet(`John`); console.log() setTimeout(() => console.log(`Hello ${name}!`, 0)); saySthNice(); console.log(`Nice to meet you.`); -
Event Loop greet() stack setTimeout API callbacks queue main() function
saySthNice():void { } function greet(name: string): void { saySthNice(); } greet(`John`); saySthNice() console.log() setTimeout(() => console.log(`Hello ${name}!`, 0)); saySthNice(); console.log(`Nice to meet you.`); -
Event Loop greet() stack setTimeout API callbacks queue main() function
saySthNice():void { } function greet(name: string): void { saySthNice(); } greet(`John`); saySthNice() console.log() console.log() setTimeout(() => console.log(`Hello ${name}!`, 0)); saySthNice(); console.log(`Nice to meet you.`); -
Event Loop greet() stack setTimeout API callbacks queue main() function
saySthNice():void { } function greet(name: string): void { saySthNice(); } greet(`John`); saySthNice() console.log() console.log() setTimeout(() => console.log(`Hello ${name}!`, 0)); saySthNice(); console.log(`Nice to meet you.`); Nice to meet you. -
Event Loop greet() stack setTimeout API callbacks queue main() function
saySthNice():void { } function greet(name: string): void { saySthNice(); } greet(`John`); saySthNice() console.log() setTimeout(() => console.log(`Hello ${name}!`, 0)); saySthNice(); console.log(`Nice to meet you.`); Nice to meet you. -
Event Loop greet() stack setTimeout API callbacks queue main() function
saySthNice():void { } function greet(name: string): void { saySthNice(); } greet(`John`); console.log() setTimeout(() => console.log(`Hello ${name}!`, 0)); saySthNice(); console.log(`Nice to meet you.`); Nice to meet you. -
Event Loop stack setTimeout API callbacks queue main() function saySthNice():void
{ } function greet(name: string): void { saySthNice(); } greet(`John`); console.log() setTimeout(() => console.log(`Hello ${name}!`, 0)); saySthNice(); console.log(`Nice to meet you.`); Nice to meet you. -
Event Loop stack setTimeout API callbacks queue function saySthNice():void {
} function greet(name: string): void { saySthNice(); } greet(`John`); console.log() setTimeout(() => console.log(`Hello ${name}!`, 0)); saySthNice(); console.log(`Nice to meet you.`); Nice to meet you. -
Event Loop stack setTimeout API callbacks queue function saySthNice():void {
} function greet(name: string): void { saySthNice(); } greet(`John`); console.log() setTimeout(() => console.log(`Hello ${name}!`, 0)); saySthNice(); console.log(`Nice to meet you.`); Nice to meet you. -
Event Loop stack setTimeout API callbacks queue function saySthNice():void {
} function greet(name: string): void { saySthNice(); } greet(`John`); console.log() setTimeout(() => console.log(`Hello ${name}!`, 0)); saySthNice(); console.log(`Nice to meet you.`); Nice to meet you. Hello John! -
Event Loop stack setTimeout API callbacks queue function saySthNice():void {
} function greet(name: string): void { saySthNice(); } greet(`John`); setTimeout(() => console.log(`Hello ${name}!`, 0)); saySthNice(); console.log(`Nice to meet you.`); Nice to meet you. Hello John! -
Case study maciejtreder.github.io/asynchronous-javascript/ [ { "id": 1, "name": "James Cameron"
}, { "id": 2, "name": "Quentin Tarantino" }, { "id": 3, "name": "Wes Anderson" }, { "id": 4, "name": "Stanley Kubrick" } ] [ { "id": 4, "title": "Django Unchained" }, { "id": 5, "title": "Inglourious Basterds" }, { "id": 6, "title": "Grindhouse" } ] { "id": 1, "reviewer": "Andy", "rating": 10 }, { "id": 2, "reviewer": "Margaret", "rating": 5 }, { "id": 3, "reviewer": "Bridget", "rating": 8 } ] /directors /directors/{id}/movies /movies/{id}/reviews -
const request = require('request'); request(`https://maciejtreder.github.io/asynchronous-javascript/ directors`, {json: true}, (err, res,body)
=> { console.log(body); }); [ { id: 1, name: 'James Cameron' }, { id: 2, name: 'Quentin Tarantino' }, { id: 3, name: 'Wes Anderson' }, { id: 4, name: 'Stanley Kubrick' } ] -
const request = require('request'); }); }); }); }); request(`https://maciejtreder.github.io/asynchronous-javascript/ directors`,
{json: true}, (err, res, directors) => { let tarantinoId = directors.find(director => director.name === "Quentin Tarantino").id; -
const request = require('request'); }); }); }); }); request(`https://maciejtreder.github.io/asynchronous-javascript/ directors`,
{json: true}, (err, res, directors) => { let tarantinoId = directors.find(director => director.name === "Quentin Tarantino").id; request(`https://maciejtreder.github.io/asynchronous-javascript/directors/${tarantinoId}/ movies`, {json: true}, (err, res, movies) => { let checkedMoviesCount = 0; -
const request = require('request'); }); }); }); }); request(`https://maciejtreder.github.io/asynchronous-javascript/ directors`,
{json: true}, (err, res, directors) => { let tarantinoId = directors.find(director => director.name === "Quentin Tarantino").id; request(`https://maciejtreder.github.io/asynchronous-javascript/directors/${tarantinoId}/ movies`, {json: true}, (err, res, movies) => { let checkedMoviesCount = 0; movies.forEach(movie => { request(`https://maciejtreder.github.io./asynchronous-javascript/movies/${movie.id}/ reviews`, {json: true}, (err, res, reviews) => { -
const request = require('request'); }); }); }); }); request(`https://maciejtreder.github.io/asynchronous-javascript/ directors`,
{json: true}, (err, res, directors) => { let tarantinoId = directors.find(director => director.name === "Quentin Tarantino").id; request(`https://maciejtreder.github.io/asynchronous-javascript/directors/${tarantinoId}/ movies`, {json: true}, (err, res, movies) => { let checkedMoviesCount = 0; movies.forEach(movie => { request(`https://maciejtreder.github.io./asynchronous-javascript/movies/${movie.id}/ reviews`, {json: true}, (err, res, reviews) => { checkedMoviesCount++; aggregatedScore = 0; reviews.forEach(review => aggregatedScore += review.rating); movie.averageRating = aggregatedScore / reviews.length; -
const request = require('request'); }); }); }); }); request(`https://maciejtreder.github.io/asynchronous-javascript/ directors`,
{json: true}, (err, res, directors) => { let tarantinoId = directors.find(director => director.name === "Quentin Tarantino").id; request(`https://maciejtreder.github.io/asynchronous-javascript/directors/${tarantinoId}/ movies`, {json: true}, (err, res, movies) => { let checkedMoviesCount = 0; movies.forEach(movie => { request(`https://maciejtreder.github.io./asynchronous-javascript/movies/${movie.id}/ reviews`, {json: true}, (err, res, reviews) => { checkedMoviesCount++; aggregatedScore = 0; reviews.forEach(review => aggregatedScore += review.rating); movie.averageRating = aggregatedScore / reviews.length; if (checkedMoviesCount === movies.length) { movies.sort((m1, m2) => m2.averageRating - m1.averageRating); console.log(`The best movie by Quentin Tarantino is... ${movies[0].title} !!!`); } -
const request = require('request'); }); }); }); }); request(`https://maciejtreder.github.io/asynchronous-javascript/ directors`,
{json: true}, (err, res, directors) => { let tarantinoId = directors.find(director => director.name === "Quentin Tarantino").id; request(`https://maciejtreder.github.io/asynchronous-javascript/directors/${tarantinoId}/ movies`, {json: true}, (err, res, movies) => { let checkedMoviesCount = 0; movies.forEach(movie => { request(`https://maciejtreder.github.io./asynchronous-javascript/movies/${movie.id}/ reviews`, {json: true}, (err, res, reviews) => { checkedMoviesCount++; aggregatedScore = 0; reviews.forEach(review => aggregatedScore += review.rating); movie.averageRating = aggregatedScore / reviews.length; if (checkedMoviesCount === movies.length) { movies.sort((m1, m2) => m2.averageRating - m1.averageRating); console.log(`The best movie by Quentin Tarantino is... ${movies[0].title} !!!`); } -
request(`https://maciejtreder.github.io/asynchronous-javascript/ directors`, {json: true}, (err, res, body) => findDirector(body, 'Quentin
Tarantino’)); function findDirector(directors, name) { let directorId = directors.find(director => director.name === name).id; request(`https://maciejtreder.github.io/asynchronous-javascript/directors/${directorId}/ movies`, {json: true}, (err, res, body) => getReviews(body, name)); } -
request(`https://maciejtreder.github.io/asynchronous-javascript/ directors`, {json: true}, (err, res, body) => findDirector(body, 'Quentin
Tarantino’)); function findDirector(directors, name) { let directorId = directors.find(director => director.name === name).id; request(`https://maciejtreder.github.io/asynchronous-javascript/directors/${directorId}/ movies`, {json: true}, (err, res, body) => getReviews(body, name)); } function getReviews(movies, director) { let checkedSoFar = {count: 0}; movies.forEach(movie => { request(`https://maciejtreder.github.io/asynchronous-javascript/movies/${movie.id}/ reviews`, {json: true}, (err, res, body) => calculateAverageScore(body, movie, director, checkedSoFar, movies )); }); } -
const request = require('request'); function findDirector(directors, name) { let directorId
= directors.find(director => director.name === name).id; request(`https://maciejtreder.github.io/asynchronous-javascript/directors/${directorId}/ movies`, {json: true}, (err, res, body) => getReviews(body, name)); function getReviews(movies, director) { let checkedSoFar = {count: 0}; movies.forEach(movie => { request(`https://maciejtreder.github.io/asynchronous-javascript/movies/${movie.id}/ reviews`, {json: true}, (err, res, body) => calculateAverageScore(body, movie, director, checkedSoFar, movies )); }); } -
const request = require('request'); function findDirector(directors, name) { let directorId
= directors.find(director => director.name === name).id; request(`https://maciejtreder.github.io/asynchronous-javascript/directors/${directorId}/ movies`, {json: true}, (err, res, body) => getReviews(body, name)); function getReviews(movies, director) { let checkedSoFar = {count: 0}; movies.forEach(movie => { request(`https://maciejtreder.github.io/asynchronous-javascript/movies/${movie.id}/ reviews`, {json: true}, (err, res, body) => calculateAverageScore(body, movie, director, checkedSoFar, movies )); }); } function calculateAverageScore(reviews, movie, director, checkedSoFar, movies) { checkedSoFar.count++; aggregatedScore = 0; count = 0; reviews.forEach(review => { aggregatedScore += review.rating; count++; }); movie.averageRating = aggregatedScore / count; if (checkedSoFar.count == movies.length) { movies.sort((m1, m2) => m2.averageRating - m1.averageRating); console.log(`The best movie by ${director} is... ${movies[0].title} !!!`); } } -
const request = require('request'); function calculateAverageScore(reviews, movie, director, checkedSoFar, movies)
{ checkedSoFar.count++; aggregatedScore = 0; count = 0; reviews.forEach(review => { aggregatedScore += review.rating; count++; }); movie.averageRating = aggregatedScore / count; if (checkedSoFar.count == movies.length) { movies.sort((m1, m2) => m2.averageRating - m1.averageRating); console.log(`The best movie by ${director} is... ${movies[0].title} !!!`); } } function getReviews(movies, director) { let checkedSoFar = {count: 0}; movies.forEach(movie => { request(`https://maciejtreder.github.io/asynchronous-javascript/movies/${movie.id}/ reviews`, {json: true}, (err, res, body) => calculateAverageScore(body, movie, director, checkedSoFar, movies)); }); } function findDirector(directors, name) { let directorId = directors.find(director => director.name === name).id; request(`https://maciejtreder.github.io/asynchronous-javascript/directors/${directorId}/ movies`, {json: true}, (err, res, body) => getReviews(body, name)); } request(`https://maciejtreder.github.io/asynchronous-javascript/ directors`, {json: true}, (err, res, body) => findDirector(body, 'Quentin Tarantino')); -
const request = require('request'); function calculateAverageScore(reviews, movie, director, checkedSoFar, movies)
{ checkedSoFar.count++; aggregatedScore = 0; count = 0; reviews.forEach(review => { aggregatedScore += review.rating; count++; }); movie.averageRating = aggregatedScore / count; if (checkedSoFar.count == movies.length) { movies.sort((m1, m2) => m2.averageRating - m1.averageRating); console.log(`The best movie by ${director} is... ${movies[0].title} !!!`); } } function getReviews(movies, director) { let checkedSoFar = {count: 0}; movies.forEach(movie => { request(`https://maciejtreder.github.io/asynchronous-javascript/movies/${movie.id}/ reviews`, {json: true}, (err, res, body) => calculateAverageScore(body, movie, director, checkedSoFar, movies)); }); } function findDirector(directors, name) { let directorId = directors.find(director => director.name === name).id; request(`https://maciejtreder.github.io/asynchronous-javascript/directors/${directorId}/ movies`, {json: true}, (err, res, body) => getReviews(body, name)); } request(`https://maciejtreder.github.io/asynchronous-javascript/ directors`, {json: true}, (err, res, body) => findDirector(body, 'Quentin Tarantino')); -
Promises const promise1 = new Promise<string>(resolve => { setTimeout(() =>
resolve(`Value from promise 1`), 1000); }); promise1.then(value => console.log(`Promise resolved with value: ${value}`)); promise1.then(value => console.log(`One more time ${value}`)); Promise resolved with value: Value from promise 1 One more time Value from promise 1 -
Promises const promise1 = new Promise<string>(resolve => { resolve(`Value from
promise 1`); resolve(`Promise resolves only once!`); }); promise1.then(value => console.log(`Promise resolved with value: ${value}`)); Promise resolved with value: Value from promise 1 -
Promises const promise2 = new Promise<string>((resolve, reject) => { reject({reason:
`Reject type doesn't depend on the Promise type, and it's always any.`}); }); promise2.then(value => {}, rejection => console.log(`Handled rejection`, rejection)); promise2.then(value => {}).catch(rejection => console.log(`Another way of handling rejection`, rejection)); Handled rejection { reason: 'Reject type doesn\'t depend on the Promise type, and it\'s always any.’} Another way of handling rejection { reason: 'Reject type doesn\'t depend on the Promise type, and it\'s always any.’} -
Promises const promise2 = new Promise<string>((resolve) => { throw {reason:
`Reject type doesn't depend on the Promise type, and it's always any.`}; }); promise2.then(value => {}, rejection => console.log(`Handled rejection`, rejection)); promise2.then(value => {}).catch(rejection => console.log(`Another way of handling rejection`, rejection)); Handled rejection { reason: 'Reject type doesn\'t depend on the Promise type, and it\'s always any.’} Another way of handling rejection { reason: 'Reject type doesn\'t depend on the Promise type, and it\'s always any.’} -
This won’t work const promise2 = new Promise<string>((resolve, reject) =>
{ reject({reason: `Reject type doesn't depend on the Promise type, and it's always any.`}); }); promise2.then(value => {}); //unhandled rejection try { promise2.then(value => {}); } catch(error) { console.log(`Catched error`); } (node:14312) UnhandledPromiseRejectionWarning: #<Object> -
Chaining promise1 .then(val => square(val)) .then(value => console.log(value)); 9 const
promise1 = Promise.resolve(3); const square = (val) => Promise.resolve(val * val); promise1.then(value => { square(value).then(value => { console.log(value); }); }); == -
Chaining promise1 .then(val => square(val)) .then(() => {throw {};}) .then(val
=> console.log(val)) .catch(error => console.log(`Catched`)) .finally(() => console.log(`Finally statement`)); Catched Finally statement -
Chaining promise1 .then(val => square(val)) .then(() => {throw null;}) .catch(error
=> { console.log(`Error in second promise`) return 1; }) .then(val => console.log(val)) .catch(error => console.log(`Catched: ${error}`)) .finally(() => console.log(`Finally statement`)); Error in second promise 1 Finally statement -
Combining const promise1 = Promise.resolve(3); const square = (val) =>
Promise.resolve(val * val); const promise2 = Promise.reject('Rejecting that!'); Promise.all([promise1, square(2)]).then(val => console.log(val)); Promise.all([promise1, square(2), promise2]) .then(val => console.log(val)) .catch(error => console.log(`Failed because of: ${error}`)); [ 3, 4 ] Failed because of: Rejecting that! -
Combining const promise1 = Promise.resolve(3); const square = (val) =>
Promise.resolve(val * val); const promise2 = Promise.reject('Rejecting that!'); Promise.all([ promise1.catch(() => undefined), square(2).catch(() => undefined ), promise2.catch(() => undefined ) ]) .then(val => console.log(val)) .catch(error => console.log(`Failed because of: ${error}`)); [ 3, 4, undefined ] -
Combining const allSettled = require('promise.allsettled'); allSettled.shim(); const promise1 = Promise.resolve(3);
const square = (val) => Promise.resolve(val * val); const promise2 = Promise.reject('Rejecting that!'); Promise.allSettled([promise1, square(2), promise2]) .then(val => console.log(val)) .catch(error => console.log(`Failed because of: ${error}`)); [ { status: 'fulfilled', value: 3 }, { status: 'fulfilled', value: 4 }, { status: 'rejected', reason: 'Rejecting that!' } ] -
Combining const promise1 = Promise.resolve(3); const square = (val) =>
Promise.resolve(val * val); const promise2 = Promise.reject('Rejecting that!'); Promise.race([promise1, square(2), promise2]) .then(val => console.log(val)) .catch(error => console.log(`Failed because of: ${error}`)); 3 -
Combining function watchDog() { return new Promise((resolve, reject) => setTimeout(()
=> reject(), 2000)); } const promise1 = Promise.resolve(3); const square = (val) => Promise.resolve(val * val); const promise2 = Promise.reject('Rejecting that!'); Promise.race([ promise2.catch(() => new Promise()), square(2), promise1, watchDog() ]) .then(val => console.log(val)) .catch(_ => console.log(`Non of the promises resolves before watchdog`)); 3 -
const fetch = require('node-fetch'); fetch(`https://maciejtreder.github.io/asynchronous-javascript/directors/`) .then(response => response.json()) .then(directors =>
{ let tarantinoId = directors.find(director => director.name === "Quentin Tarantino").id; return fetch(`https://maciejtreder.github.io/asynchronous-javascript/directors/${tarantinoId}/ movies`); }) .then(response => response.json()) Quentin Movies -
const fetch = require('node-fetch'); fetch(`https://maciejtreder.github.io/asynchronous-javascript/directors/`) .then(response => response.json()) .then(directors =>
{ let tarantinoId = directors.find(director => director.name === "Quentin Tarantino").id; return fetch(`https://maciejtreder.github.io/asynchronous-javascript/directors/${tarantinoId}/ movies`); }) .then(response => response.json()) .then(movies => { let reviewsArr = []; movies.forEach(movie => { reviewsArr.push( fetch(`https://maciejtreder.github.io/asynchronous-javascript/movies/${movie.id}/ reviews`) .then(response => response.json()).then(reviews => { return {movie: movie, reviews: reviews}; }) ); }); return Promise.all(reviewsArr); }) [{title: movie, reviews: []}] -
return fetch(`https://maciejtreder.github.io/asynchronous-javascript/directors/${tarantinoId}/ movies`); }) .then(response => response.json()) .then(movies => {
let reviewsArr = []; movies.forEach(movie => { reviewsArr.push( fetch(`https://maciejtreder.github.io/asynchronous-javascript/movies/${movie.id}/ reviews`) .then(response => response.json()).then(reviews => { return {movie: movie, reviews: reviews}; }) ); }); return Promise.all(reviewsArr); }) [{title: movie, reviews: []}] -
return fetch(`https://maciejtreder.github.io/asynchronous-javascript/directors/${tarantinoId}/ movies`); }) .then(response => response.json()) .then(movies => {
let reviewsArr = []; movies.forEach(movie => { reviewsArr.push( fetch(`https://maciejtreder.github.io/asynchronous-javascript/movies/${movie.id}/ reviews`) .then(response => response.json()).then(reviews => { return {movie: movie, reviews: reviews}; }) ); }); return Promise.all(reviewsArr); }) .then(reviewSets => { let moviesAndRatings = []; reviewSets.forEach(reviews => { let aggregatedScore = 0; reviews.reviews.forEach( review => aggregatedScore += review.rating ); let averageScore = aggregatedScore / reviews.reviews.length; moviesAndRatings.push({title: reviews.movie, averageScore: averageScore}); }); return moviesAndRatings.sort((m1, m2) => m2.averageScore - m1.averageScore)[0].title; }) .then(movie => console.log(` ${movie.title} !`)) [{title: movie, averageScore: score}] -
fetch(`/directors/`) /directors /directors/2/movies .then(directors => { let tarantinoId = directors.findTarantino();
return fetch(`/directors/${tarantinoId}/movies`); }) /movies/{id}/reviews .then(movies => { let reviewsArr = fetchAllReviews(movies); return Promise.all(reviewsArr); }) .then(reviewSets => { let moviesAndRatings = calculateAverageScores(reviewSets); return moviesAndRatings.sort((m1, m2) => m2.aver ageScore - m1.averageScore)[0].title; }) .then(movie => console.log(`The best movie by Quen tin Tarantino is... ${movie.title}!`)); -
import { Observable, Observer } from 'rxjs'; const clock$: Observable<string>
= Observable.create((observer: Observer<string>) => { console.log('In Observable'); setInterval(() => { observer.next('tick'); }, 1000); }); RxJS clock$.subscribe(val => console.log(val)); In Observable; tick; tick; tick; tick; … -
RxJS const clock$: Subject<string> = new Subject<string>(); const interval =
setInterval(() => { clock$.next('tick'); }, 1000); tick; tick let subscription = clock$.subscribe(val => console.log(val)); setTimeout(() => subscription.unsubscribe(), 3 * 1000); -
RxJS const clock$: Subject<string> = new Subject<string>(); const interval =
setInterval(() => { clock$.next('tick'); }, 1000); tick; tick setTimeout(() => clock$.complete(), 8 * 1000); setTimeout(() => clearInterval(interval), 9 * 1000); let subscription = clock$.subscribe(val => console.log(val)); setTimeout(() => subscription.unsubscribe(), 3 * 1000); setTimeout(() => subscription = clock$.subscribe(val => console.log(val)), 4*1000); tick; tick; tick; tick -
Manipulating data const clock$: Subject<string> = new Subject<string>(); const interval
= setInterval(() => { clock$.next('tick'); }, 1000); setTimeout(() => clock$.complete(), 8 * 1000) setTimeout(() => clearInterval(interval), 9 * 1000); tick; tock; tick; tock; tick; tock; tick; tock clock$.pipe( map((val, index) => index % 2 == 0 ? val : 'tock') ).subscribe(val => console.log(val)); import { map } from 'rxjs/operators'; -
Error catching import { , Subject } from 'rxjs'; import
{ map, } from ‘rxjs/operators'; const clock$: Subject<string> = new Subject<string>(); const interval = setInterval(() => { clock$.next('tick'); }, 1000); setTimeout(() => clock$.complete(), 8 * 1000); setTimeout(() => clearInterval(interval), 9 * 1000); clock$.pipe( map((val, index) => index % 2 == 0 ? val : ‘tock’), ).subscribe(val => console.log(val)); tick; tock; tick; tock; setTimeout(() => console.log('Still alive?'), 12 * 1000); -
Error catching import { , Subject } from 'rxjs'; import
{ map, } from ‘rxjs/operators'; const clock$: Subject<string> = new Subject<string>(); const interval = setInterval(() => { clock$.next('tick'); }, 1000); setTimeout(() => clock$.complete(), 8 * 1000); setTimeout(() => clearInterval(interval), 9 * 1000); clock$.pipe( map((val, index) => index % 2 == 0 ? val : ‘tock’), ).subscribe(val => console.log(val)); tick; tock; tick; tock; Error: BOOOM! setTimeout(() => clock$.error(new Error('BOOOM!')), 5 * 1000); setTimeout(() => console.log('Still alive?'), 12 * 1000); -
Error catching import { , Subject } from 'rxjs'; import
{ map, } from ‘rxjs/operators'; const clock$: Subject<string> = new Subject<string>(); const interval = setInterval(() => { clock$.next('tick'); }, 1000); setTimeout(() => clock$.complete(), 8 * 1000); setTimeout(() => clearInterval(interval), 9 * 1000); clock$.pipe( map((val, index) => index % 2 == 0 ? val : ‘tock’), ).subscribe(val => console.log(val)); tick; tock; tick; tock; setTimeout(() => clock$.error(new Error('BOOOM!')), 5 * 1000); setTimeout(() => console.log('Still alive?'), 12 * 1000); catchError(error => of('Explosion!')) catchError of Explosion! Still alive? -
Error catching import { , Subject } from 'rxjs'; import
{ map, } from ‘rxjs/operators'; const clock$: Subject<string> = new Subject<string>(); const interval = setInterval(() => { clock$.next('tick'); }, 1000); setTimeout(() => clock$.complete(), 8 * 1000); setTimeout(() => clearInterval(interval), 9 * 1000); clock$.pipe( map((val, index) => index % 2 == 0 ? val : ‘tock’), ).subscribe(val => console.log(val)); tick; tock; tick; tock; setTimeout(() => clock$.error(new Error('BOOOM!')), 5 * 1000); setTimeout(() => console.log('Still alive?'), 12 * 1000); catchError(error => of('Explosion!')) catchError of Explosion! Still alive? -
RxJS 12 6 3 9 1 2 4 5 7
8 10 11 tick tick tick tick tick tick tick tick tick tick tick tock tick tock tick tock tick tock BOOM! Explosion! Still alive? import { of, Subject } from 'rxjs'; import { map, catchError } from ‘rxjs/operators'; const clock$: Subject<string> = new Subject<string>(); const interval = setInterval(() => { clock$.next('tick'); }, 1000); setTimeout(() => clock$.error(new Error('BOOOM!')), 5 * 1000) setTimeout(() => clearInterval(interval), 6 * 1000); clock$.pipe( map((val, index) => index % 2 == 0 ? val : 'tock'), catchError(error => of('Explosion!')) ).subscribe(val => console.log(val)); setTimeout(() => console.log('Still alive?'), 12 * 1000); -
RxJS & REST const Axios = require('axios-observable').Axios; const map =
require('rxjs/operators').map; const flatMap = require('rxjs/operators').flatMap; const combineLatest = require('rxjs').combineLatest; Axios.get('https://maciejtreder.github.io/asynchronous-javascript/directors/') .pipe( map(response => response.data), List of directors -
RxJS & REST const Axios = require('axios-observable').Axios; const map =
require('rxjs/operators').map; const flatMap = require('rxjs/operators').flatMap; const combineLatest = require('rxjs').combineLatest; Axios.get('https://maciejtreder.github.io/asynchronous-javascript/directors/') .pipe( map(response => response.data), map(response => response.find(director => director.name == 'Quentin Tarantino').id), flatMap(id => Axios.get(`https://maciejtreder.github.io/asynchronous-javascript/directors/ ${id}/movies`)), map(response => response.data), Quentin Movies -
RxJS & REST const Axios = require('axios-observable').Axios; const map =
require('rxjs/operators').map; const flatMap = require('rxjs/operators').flatMap; const combineLatest = require('rxjs').combineLatest; Axios.get('https://maciejtreder.github.io/asynchronous-javascript/directors/') .pipe( map(response => response.data), map(response => response.find(director => director.name == 'Quentin Tarantino').id), flatMap(id => Axios.get(`https://maciejtreder.github.io/asynchronous-javascript/directors/ ${id}/movies`)), map(response => response.data), flatMap(movies => { const observables$ = []; movies.forEach(movie => { Quentin Movies -
RxJS & REST map(response => response.data), map(response => response.find(director =>
director.name == 'Quentin Tarantino').id), flatMap(id => Axios.get(`https://maciejtreder.github.io/asynchronous-javascript/directors/ ${id}/movies`)), map(response => response.data), flatMap(movies => { const observables$ = []; movies.forEach(movie => { Quentin Movies -
RxJS & REST map(response => response.data), map(response => response.find(director =>
director.name == 'Quentin Tarantino').id), flatMap(id => Axios.get(`https://maciejtreder.github.io/asynchronous-javascript/directors/ ${id}/movies`)), map(response => response.data), flatMap(movies => { const observables$ = []; movies.forEach(movie => { observables$.push( Axios.get(`https://maciejtreder.github.io/asynchronous-javascript/movies/$ {movie.id}/reviews`) .pipe( map(response => response.data), map(reviews => { let count = 0; let sum = 0; reviews.forEach(review => {count++; sum+=review.score}); return sum/reviews.length; }), map(average => { return {title: movie.title, averageScore: average}; }) ) ); }); Quentin Movies -
RxJS & REST map(response => response.data), map(response => response.find(director =>
director.name == 'Quentin Tarantino').id), flatMap(id => Axios.get(`https://maciejtreder.github.io/asynchronous-javascript/directors/ ${id}/movies`)), map(response => response.data), flatMap(movies => { const observables$ = []; movies.forEach(movie => { observables$.push( Axios.get(`https://maciejtreder.github.io/asynchronous-javascript/movies/$ {movie.id}/reviews`) .pipe( map(response => response.data), map(reviews => { let count = 0; let sum = 0; reviews.forEach(review => {count++; sum+=review.score}); return sum/reviews.length; }), map(average => { return {title: movie.title, averageScore: average}; }) ) ); }); return combineLatest(observables$); }), map(movies => movies.sort((movie1, movie2) => movie2.averageScore - movie1.averageScore)), map(movies => movies[0].title) ) [{title: movie, averageScore: score}] -
RxJS & REST map(response => response.data), map(response => response.find(director =>
director.name == 'Quentin Tarantino').id), flatMap(id => Axios.get(`https://maciejtreder.github.io/asynchronous-javascript/directors/ ${id}/movies`)), map(response => response.data), flatMap(movies => { const observables$ = []; movies.forEach(movie => { observables$.push( Axios.get(`https://maciejtreder.github.io/asynchronous-javascript/movies/$ {movie.id}/reviews`) .pipe( map(response => response.data), map(reviews => { let count = 0; let sum = 0; reviews.forEach(review => {count++; sum+=review.score}); return sum/reviews.length; }), map(average => { return {title: movie.title, averageScore: average}; }) ) ); }); return combineLatest(observables$); }), map(movies => movies.sort((movie1, movie2) => movie2.averageScore - movie1.averageScore)), map(movies => movies[0].title) ) .subscribe(console.log); [{title: movie, averageScore: score}] -
RxJS pros const Axios = require('axios-observable').Axios; const map = require('rxjs/operators').map;
const retry = require('rxjs/operators').retry; Axios.get('https://maciejtreder.github.io/asynchronous-javascript/directors/123') .pipe( map(resp => resp.data) ) .subscribe(console.log); retry(3), -
RxJS pros const Axios = require('axios-observable').Axios; const map = require('rxjs/operators').map;
const retry = require('rxjs/operators').retry; Axios.get('https://maciejtreder.github.io/asynchronous-javascript/directors/123') .pipe( map(resp => resp.data) ) .subscribe(console.log); retry(3), -
Tracking the ISS with Real-Time Event Notifications Using Node.js, RxJS
Observables, and Twilio Programmable SMS https://www.twilio.com/blog/real-time-event-notifications-using-node-js-rxjs-observables-twilio-programmable-sms -
Make the code synchronous again const getMultiplier = Promise.resolve(2); const
multiply = (multiply, multiplier) => Promise.resolve(multiply * multiplier); let multiplier = getMultiplier; let result = multiply(10, multiplier); console.log(`Multiply result: ${result}`); getMultiplier .then(value => multiply(10, value)) .then(result => console.log(`Multiply result: ${result}`)); await await var multiplier = await getMultiplier; ^^^^^ SyntaxError: await is only valid in async function at new Script (vm.js:79:7) at createScript (vm.js:251:10) at Object.runInThisContext (vm.js:303:10) at Module._compile (internal/modules/cjs/loader.js:657:28) at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10) at Module.load (internal/modules/cjs/loader.js:599:32) at tryModuleLoad (internal/modules/cjs/loader.js:538:12) at Function.Module._load (internal/modules/cjs/loader.js:530:3) at Function.Module.runMain (internal/modules/cjs/loader.js:742:12) at startup (internal/bootstrap/node.js:283:19) -
Make the code asynchronous again! const multiplier = getMultiplier; const
result = multiply(10, multiplier); console.log(`Multiply result: ${result}`); await await (async () => { })(); async function myFunction() { return "someValue"; } == function myFunction() { return Promise.resolve("someValue"); } Multiply result: 20 const getMultiplier = Promise.resolve(2); const multiply = (multiply, multiplier) => Promise.resolve(multiply * multiplier); -
vs let multiplier = getMultiplier; let result = multiply(10, multiplier);
console.log(`Multiply result: ${result}`); await await (async () => { })(); getMultiplier .then(value => multiply(10, value)) .then(result => console.log(`Multiply result: ${result}`)); -
async-await and RxJS import { Subject } from 'rxjs'; const
clock$: Subject<number> = new Subject<number>(); let i = 0; const interval = setInterval(() => { clock$.next(i++); }, 1000); setTimeout(() => clock$.complete(), 4*1000); setTimeout(() => clearInterval(interval), 5 * 1000); (async () => { console.log(await clock$.toPromise()); })(); 2 -
async-await error catching const promise = Promise.reject('rejection reason'); (async ()
=> { try { console.log(await promise); } catch (err) { console.log(`Error catched: ${err}`); } finally { console.log('Finally executes'); } })(); Error catched: rejection reason Finally executes -
const fetch = require('node-fetch'); (async () => { })(); const
directors = await fetch(`https://maciejtreder.github.io/asynchronous-javascript/directors/`) .then(response => response.json()); const tarantinoId = directors.find(director => director.name === "Quentin Tarantino").id; -
const fetch = require('node-fetch'); (async () => { })(); const
directors = await fetch(`https://maciejtreder.github.io/asynchronous-javascript/directors/`) .then(response => response.json()); const tarantinoId = directors.find(director => director.name === "Quentin Tarantino").id; const quentinMovies = await fetch(`https://maciejtreder.github.io/asynchronous-javascript/ directors/${tarantinoId}/movies`) .then(response => response.json()); -
const fetch = require('node-fetch'); (async () => { })(); const
directors = await fetch(`https://maciejtreder.github.io/asynchronous-javascript/directors/`) .then(response => response.json()); const tarantinoId = directors.find(director => director.name === "Quentin Tarantino").id; const quentinMovies = await fetch(`https://maciejtreder.github.io/asynchronous-javascript/ directors/${tarantinoId}/movies`) .then(response => response.json()); const reviewsCall = []; quentinMovies.forEach(movie => { reviewsCall.push(fetch(`https://maciejtreder.github.io/asynchronous-javascript/movies/$ {movie.id}/reviews`) .then(resp => resp.json()) .then(resp => { return {title: movie.title, reviews: resp}; })); }); const reviews = await Promise.all(reviewsCall); -
const fetch = require('node-fetch'); (async () => { })(); const
directors = await fetch(`https://maciejtreder.github.io/asynchronous-javascript/directors/`) .then(response => response.json()); const tarantinoId = directors.find(director => director.name === "Quentin Tarantino").id; const quentinMovies = await fetch(`https://maciejtreder.github.io/asynchronous-javascript/ directors/${tarantinoId}/movies`) .then(response => response.json()); const reviewsCall = []; quentinMovies.forEach(movie => { reviewsCall.push(fetch(`https://maciejtreder.github.io/asynchronous-javascript/movies/$ {movie.id}/reviews`) .then(resp => resp.json()) .then(resp => { return {title: movie.title, reviews: resp}; })); }); const reviews = await Promise.all(reviewsCall); reviews.forEach(entry => { let aggregatedScore = 0; entry.reviews.forEach(review => aggregatedScore += review.rating); entry.score = aggregatedScore / entry.reviews.length; }); const best = reviews.sort((movie1, movie2) => movie2.score - movie1.score)[0].title; console.log(`The best movie by Quentin Tarantino is ${best}`); -
const fetch = require('node-fetch'); (async () => { })(); const
directors = await fetch(`https://maciejtreder.github.io/asynchronous-javascript/directors/`) .then(response => response.json()); const tarantinoId = directors.find(director => director.name === "Quentin Tarantino").id; const quentinMovies = await fetch(`https://maciejtreder.github.io/asynchronous-javascript/ directors/${tarantinoId}/movies`) .then(response => response.json()); const reviewsCall = []; quentinMovies.forEach(movie => { reviewsCall.push(fetch(`https://maciejtreder.github.io/asynchronous-javascript/movies/$ {movie.id}/reviews`) .then(resp => resp.json()) .then(resp => { return {title: movie.title, reviews: resp}; })); }); const reviews = await Promise.all(reviewsCall); reviews.forEach(entry => { let aggregatedScore = 0; entry.reviews.forEach(review => aggregatedScore += review.rating); entry.score = aggregatedScore / entry.reviews.length; }); const best = reviews.sort((movie1, movie2) => movie2.score - movie1.score)[0].title; console.log(`The best movie by Quentin Tarantino is ${best}`); -
Performance pitfall function promiseFunction1() { return new Promise(resolve => {
setTimeout(() => { resolve("abc"); }, 2000); }); } function promiseFunction2() { return new Promise(resolve => { setTimeout(() => { resolve("abc"); }, 2000); }); } (async () => { console.log(await promiseFunction1()); console.log(await promiseFunction2()); })(); (async () => { const promisefn1 = promiseFunction1(); const promisefn2 = promiseFunction2(); console.log(await promisefn1); console.log(await promisefn2); })(); 2 sec 4 sec -
Callbacks RxJS Promises async-await asynchronous synchronous? asynchronous asynchronous repeatable one-shot
repeatable (not) reusable reusable reusable (not) manipulatable manipulatable manipulatable REST WebSocket Dependent operations DOM events