From c3e6d96574c465c7eaafca2b972aca129d14b714 Mon Sep 17 00:00:00 2001 From: gajduk-mansystems Date: Sun, 8 Mar 2020 13:57:43 +0100 Subject: [PATCH 1/2] Lesson plan 3 update promise exercise --- Week2/LESSONPLAN.md | 213 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 171 insertions(+), 42 deletions(-) diff --git a/Week2/LESSONPLAN.md b/Week2/LESSONPLAN.md index 1ec8ea38c..ed3334ee4 100644 --- a/Week2/LESSONPLAN.md +++ b/Week2/LESSONPLAN.md @@ -18,41 +18,129 @@ FIRST HALF (12.00 - 13.30) - It's a way to introduce asynchronicity to your application - Makes asynchronous code read like it's synchronous ### Example + +In the examples `setTimeout` is used to illustrate asynchronous code. In the real world there will be some code doing useful work here, for example `fetch`. + +**Callback** ```javascript -let promiseToDoHomeWork = new Promise(function (resolve, reject) { - let isDone = true; +let doHomeWork = function (cb) { + setTimeout(function () { + if ( true ) + cb(); // homework done + else + cb('homework not done, too lazy'); + }, 1000); +} - if (isDone) { - resolve('homework is done!'); - } else { - reject('not done!'); - } + +doHomeWork(function (err) { + if ( err ) + console.warn(err); + else + console.log('home work is done now'); +}) +``` + +**Promise** +```javascript +let promiseToDoHomeWork = new Promise(function (resolve, reject) { + setTimeout(function () { + if ( true ) + resolve(); // homework done + else + reject('homework not done, too lazy'); + }, 1000); }); promiseToDoHomeWork .then(function () { console.log('home work is done now'); }) - .catch(function () { console.log('home work has something wrong, can\'t be done'); }) + .catch(function (err) { console.warn(err); }) + +``` +#### Nested callback/promises example + +```javascript +let attendClass = function (cb) { + setTimeout(function () { + if ( true ) + cb(null, 'I attend the class'); + else + cb('class not attended, stayed home'); + }, 1000); +} + +let doTheHomeWork = function (message, cb) { + setTimeout(function () { + if ( true ) + cb(null, message + ' then I did the homework'); + else + cb('homework not done, was lazy'); + }, 1000); +} +let submitHomeWork = function (message, cb) { + setTimeout(function () { + if ( true ) + cb(null, message + ' so I submit my homework'); + else + cb('homework not submited, github is down'); + }, 1000); +} + +// call attendClass, after it is finished call doTheHomeWork then submitHomeWork. In each step pass the output of the previous step. In case of an error show it in the console + +attendClass(function (err, data) { + if ( err ) + console.warn(err); + else + doTheHomeWork(data, function (err1, data1) { + if ( err1 ) + console.warn(err1); + else + submitHomeWork(data1, function (err2, data2) { + if ( err2 ) + console.warn(err2); + else + console.log(data2) + }); + }) +}) ``` -- Nested promises example +Mention how this nested structure is hard to understand and read. Multiple variables with similar names and error handling is all over the place. +Simulate an error in doTheHomeWork by replacing `if ( true )` with `if ( false )`. ```javascript let attendClass = function () { return new Promise(function (resolve, reject) { - resolve('I attend the class'); + setTimeout(function () { + if ( true ) + resolve('I attend the class'); + else + reject('class not attended, stayed home'); + }, 1000); }); } let doTheHomeWork = function (message) { return new Promise(function (resolve, reject) { - resolve(message + 'then I did the homework'); + setTimeout(function () { + if ( true ) + resolve(message + ' then I did the homework'); + else + reject('homework not done, was lazy'); + }, 1000); }); } -let submitHomework = function (message) { +let submitHomeWork = function (message) { return new Promise(function (resolve, reject) { - resolve(message + 'so I submit my homework'); + setTimeout(function () { + if ( true ) + resolve(message + ' so I submit my homework'); + else + reject('homework not submited, github is down'); + }, 1000);; }); } @@ -60,14 +148,19 @@ attendClass() .then(function (result) { return doTheHomeWork(result); }) - .then(function () { - return submitHomework(result); - }).catch(function (error) { - console.log(error); + .then(function (result) { + return submitHomeWork(result); + }) + .then(function (result) { + console.log(result); + }) + .catch(function (error) { + console.warn(error); }); -``` +``` +Simulate an error in doTheHomeWork by replacing `if ( true )` with `if ( false )` and run the example again. - Promise.all @@ -81,39 +174,75 @@ Promise.all([attendClass(), doTheHomeWork(), submitHomework()]).then(function ([ Promise.race([attendClass(), doTheHomeWork(), submitHomework()]).then(function (result) { console.log('one of them finished') }); ``` -- Example for converting XHR to promise as a preparation for `fetch` +### Exercise + +#### Easy exercise (see difficult exercise alternative below) + +**Part 1** +Rewrite the following code to use promise instead of callbacks. *As preparation for `fetch`* ```javascript -function fetchResource(url) { - return new Promise(function (resolve, reject) { - const oReq = new XMLHttpRequest(); - oReq.open('GET', url); - oReq.send(); - oReq.addEventListener('load', function (event) { - const data = JSON.parse(this.response); - if (data.cod >= 400) { - // error - console.log('error', data); - reject(data); - } else { - //success - console.log('success', data); - resolve(data); - } - }); +{ +const WEATHER_URL = `https://api.openweathermap.org/data/2.5/weather?q=amsterdam&appid=316f8218c0899311cc029a305f39575e`; + +function fetchResourceAsCallback(url, cb) { + const oReq = new XMLHttpRequest(); + oReq.open('GET', url); + oReq.send(); + oReq.addEventListener('load', function (event) { + const response = JSON.parse(this.response); + if (response.code >= 400) { + // error + cb("Failed to get because:"+response); + } else { + //success + cb(null, response); + } }); } -fetchResource(`https://api.openweathermap.org/data/2.5/weather?q=amsterdam&appid=316f8218c0899311cc029a305f39575e`).then(function (result) { +fetchResourceAsCallback(WEATHER_URL, + function (err, data) { + if ( err ) + console.warn(err); + else + console.log(data); + } +); + +function fetchResourceAsPromise(url) { + // your code goes in here +} + +fetchResourceAsPromise(WEATHER_URL).then(function (result) { console.log(result); +}) +.catch(function (err) { + console.warn(err); }); +} ``` -### Excercise +**Part 2** + +Use `Promise.all` to load data for multiple cities in parallel. Ask students to discuss in which scenarios it would be better to load data in parallel. In what scenarios is loading data in parallel not better. + +```javascript + +const URLS_TO_LOAD = [ 'https://samples.openweathermap.org/data/2.5/weather?q=London&appid=316f8218c0899311cc029a305f39575e', 'https://api.openweathermap.org/data/2.5/weather?q=amsterdam&appid=316f8218c0899311cc029a305f39575e']; +``` + +* Hint: use `map` to convert from an array of URLs to an array of promises. + +**Alternative exercise - Cooking pasta** + +**❗❗❗ Difficult exercise ❗❗❗** + > Async can be hard to understand without real live example. Cooking is a great example of mixed synchronous and asynchronous tasks. In this assignment we'll cook pasta with promises 💍 -Let's say we want a programme to cook some pasta. Some of the steps involved in cooking pasta are: + +Let's say we want a program to cook some pasta. Some of the steps involved in cooking pasta are: 1. Gathering the ingredients (pasta, garlic, tomatoes, sage, butter) 2. Cutting the garlic @@ -124,7 +253,7 @@ Let's say we want a programme to cook some pasta. Some of the steps involved in 7. Baking the tomatoes X. Mixing the pasta with sauce -If we do this synchronolously there is no chance of it becoming a good meal because the pasta would be cold by the time the vegetables are ready. It would also take way too long this way. So let's fix that! +If we do this synchronously there is no chance of it becoming a good meal because the pasta would be cold by the time the vegetables are ready. It would also take way too long this way. So let's fix that! 1. Think about how to do this asynchronously; which tasks could be run at the same time? What steps should wait for what other steps? Try to write down a basic recipe (don't write any code yet!) 2. Now convert your recipe to pseudocode (in markdown). The point is to name functions and show which functions call which other functions. The logic should be there but we'll write the code in the next step. @@ -142,7 +271,7 @@ If we do this synchronolously there is no chance of it becoming a good meal beca ### Essence - It's the accepted solution to [callback hell](http://callbackhell.com/) - +- in terms of features it does not offer something new, everything one can do with promises could also be done with callbacks but it is easier to write and read the code when promises are used ## 2. How to use the `fetch` API to do AJAX calls @@ -170,7 +299,7 @@ SECOND HALF (14.00 - 16.00) ## 3. The `this` keyword and its relationship with `scope` ### Explanation -- The environment(or scope) in which the line is being executed is know as “Execution Context” +- The environment(or scopeis knownich the line is being executed is know as “Execution Context” - The object that `this` refers to, changes every time execution context is changed. - Whatever is calling the function passes the `this` value to it by default. - We can pass specific `this` by `.bind`, `.call` or `.apply` From bb888a0b9eec33cef02eed6eea1a9d7ba7dae960 Mon Sep 17 00:00:00 2001 From: gajduk-mansystems Date: Sun, 8 Mar 2020 14:02:44 +0100 Subject: [PATCH 2/2] fixed some typos --- Week2/LESSONPLAN.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Week2/LESSONPLAN.md b/Week2/LESSONPLAN.md index ed3334ee4..6efdf5ea6 100644 --- a/Week2/LESSONPLAN.md +++ b/Week2/LESSONPLAN.md @@ -299,7 +299,7 @@ SECOND HALF (14.00 - 16.00) ## 3. The `this` keyword and its relationship with `scope` ### Explanation -- The environment(or scopeis knownich the line is being executed is know as “Execution Context” +- The environment(or scope) in which the line is being executed is know as “Execution Context” - The object that `this` refers to, changes every time execution context is changed. - Whatever is calling the function passes the `this` value to it by default. - We can pass specific `this` by `.bind`, `.call` or `.apply` @@ -440,7 +440,7 @@ person2Display(); // Prints Name: Paul Adams The this keyword works differently in arrow functions. -- The `this` value inside the arrow function gets binded and calcuated and assigned based on its wrapper/container/parent `this` value. +- The `this` value inside the arrow function gets binded and calculated and assigned based on its wrapper/container/parent `this` value. - The methods call(), apply(), and bind() will not change the value of this in arrow functions ### Example ```javascript