Asynchronous JavaScript - there and back again

Asynchronous JavaScript - there and back again

6e98c4f0f46eb0bf48148e83067a4391?s=128

Maciej Treder

June 10, 2020
Tweet

Transcript

  1. @maciejtreder Asynchronous and Synchronous JavaScript. There and back again.

  2. single thread == single action

  3. 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.
  4. 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!
  5. Those are not part of JavaScript • setTimeout • setInterval

    • fetch • DOM • window
  6. 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.`);
  7. 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.`);
  8. 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.`);
  9. 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.`);
  10. 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.`);
  11. 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.`);
  12. 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.`);
  13. 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.`);
  14. 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.`);
  15. 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.`);
  16. 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.`);
  17. 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.
  18. 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.
  19. 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.
  20. 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.
  21. 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.
  22. 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.
  23. 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!
  24. 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!
  25. 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
  26. 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' } ]
  27. const request = require('request'); }); }); }); });

  28. 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;
  29. 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;
  30. 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) => {
  31. 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;
  32. 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} !!!`); }
  33. 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} !!!`); }
  34. 3 REST calls & 8 nested levels

  35. request(`https://maciejtreder.github.io/asynchronous-javascript/ directors`, {json: true}, (err, res, body) => findDirector(body, 'Quentin

    Tarantino’));
  36. 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)); }
  37. 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 )); }); }
  38. 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 )); }); }
  39. 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} !!!`); } }
  40. 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'));
  41. 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'));
  42. Understanding callbacks https://www.twilio.com/blog/asynchronous-javascript-understanding-callbacks

  43. Organizing Callbacks for Readability and Reusability https://www.twilio.com/blog/asynchronous-javascript-organize-callbacks-readability-reusability

  44. Promises

  45. 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
  46. 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
  47. 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.’}
  48. 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.’}
  49. 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>
  50. 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); }); }); ==
  51. 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
  52. 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
  53. 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!
  54. 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 ]
  55. 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!' } ]
  56. 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
  57. 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
  58. const fetch = require('node-fetch'); fetch(`https://maciejtreder.github.io/asynchronous-javascript/directors/`) .then(response => response.json()) List of

    directors
  59. 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
  60. 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: []}]
  61. 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: []}]
  62. 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}]
  63. 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}!`));
  64. Introduction to JavaScript Promises https://www.twilio.com/blog/asynchronous-javascript-introduction-promises

  65. Advanced Promises with Node.js https://www.twilio.com/blog/asynchronous-javascript-advanced-promises-chaining-collections-nodejs

  66. Introduction to JavaScript Promises https://www.twilio.com/blog/asynchronous-javascript-refactor-callbacks-promises-node-js

  67. RxJS

  68. 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; …
  69. 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);
  70. 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
  71. 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';
  72. 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);
  73. 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);
  74. 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?
  75. 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?
  76. 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);
  77. 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
  78. 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
  79. 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
  80. 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
  81. 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
  82. 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}]
  83. 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}]
  84. 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),
  85. 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),
  86. Introducing ReactiveX and RxJS Observables https://www.twilio.com/blog/asynchronous-javascript-reactivex-rxjs-observables-nodejs

  87. Using RxJS Observables with REST APIs in Node.js https://www.twilio.com/blog/asynchronous-javascript-refactor-callbacks-promises-node-js

  88. 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
  89. Which Operator to Use? https://xgrommx.github.io/rx-book/content/which_operator_do_i_use/index.html

  90. callback, then(), subscribe() …

  91. Make the code synchronous again

  92. 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)
  93. 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);
  94. 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}`));
  95. 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
  96. 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
  97. const fetch = require('node-fetch'); (async () => { })();

  98. 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;
  99. 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());
  100. 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);
  101. 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}`);
  102. 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}`);
  103. 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
  104. Introducing async and await https://www.twilio.com/blog/asynchronous-javascript-introducing-async-and-await

  105. Using Promises With REST APIs in Node.js https://www.twilio.com/blog/asynchronous-javascript-using-promises-rest-apis-nodejs

  106. 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
  107. Feedback https://bit.ly/2UthmIy

  108. @maciejtreder