From 5a3189be56cc880a4662a96ac275af5637f882e7 Mon Sep 17 00:00:00 2001 From: Dedekind561 Date: Tue, 28 Nov 2023 09:10:13 +0000 Subject: [PATCH 01/12] save work in progress --- content/js3/blocks/asynchronicity/index.md | 76 ++++++++++++++++++++++ content/js3/blocks/chaining/index.md | 51 +++++++++++++++ content/js3/blocks/fetch/index.md | 29 +++++++++ content/js3/blocks/fetching-data/index.md | 23 +++++++ content/js3/blocks/internet/index.md | 26 ++++++++ content/js3/blocks/using-fetch/index.md | 26 ++++++++ content/js3/sprints/2/prep/index.md | 14 +++- 7 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 content/js3/blocks/asynchronicity/index.md create mode 100644 content/js3/blocks/chaining/index.md create mode 100644 content/js3/blocks/fetch/index.md create mode 100644 content/js3/blocks/fetching-data/index.md create mode 100644 content/js3/blocks/internet/index.md create mode 100644 content/js3/blocks/using-fetch/index.md diff --git a/content/js3/blocks/asynchronicity/index.md b/content/js3/blocks/asynchronicity/index.md new file mode 100644 index 000000000..1db171e03 --- /dev/null +++ b/content/js3/blocks/asynchronicity/index.md @@ -0,0 +1,76 @@ ++++ +title = 'Asynchronicity' +headless = true +time = 20 +facilitation = false +emoji= '🧩' +[objectives] ++++ + +We can call functions and can store their return values in variables. However, storing the return value of `fetch` doesn't give us direct access to the film data that we need. + +```js +const filmData = fetch("https://api-film-data.com/films"); +console.log(filmData); // filmData not available here +``` + +`fetch `is an **asynchronous** function. `fetch` needs to request information across a network and requests like this take time. The length of time for the request to finish depends on lots of external factors such as how fast the external server processes our request. Such factors are beyond our control. When `fetch` is called, we still need other parts of our program. We cannot wait around for a network request to finish before we start handling other tasks in our application. To handle this asynchronicity, we can use {{}}A **Promise** is a JavaScript object that enables us to access the eventual outcome of an asynchronous task{{}}. + +### Promise object + +Promise objects are in one of three different states: + +- **pending** - this means the asynchronous task is waiting / not completed +- **fulfilled** - the async task succeeded +- **rejection** - the async task failed + +### On fulfilment + +Let's consider our example again: + +```js +fetch("https://api-film-data.com/films"); // this is a Promise object +``` + +`fetch` **returns** a Promise object. When the Promise is first created, its state will be **pending** ( as the network request hasn't completed ). + +> πŸ’‘ However, we'll need to execute some code when if the async task is successful. In other words, we'll need to execute some code when the Promise state moves from **pending** -> **fulfilled**. + +To run some code when the network request is successful, we can use a special function called `then` available on the Promise object. `then` takes a function as an argument that is called automatically once the Promise's state is fulfilled. + +```js +fetch("https://api-film-data.com/films").then(function runOnFulfilment(data) { + console.log(data); +}); + +console.log("another log..."); +``` + +Let's break down what's happening here. +`then` is passed a callback function defined as `runOnFulfilment`: + +```js +function runOnFulfilment(data) { + console.log(data); +} +``` + +We're also logging outside of this function too: + +```js {linenos=table,hl_lines=["5"],linenostart=1} +fetch("https://api-film-data.com/films").then(function runOnFulfilment(data) { + console.log("running the callback function after fetch completes..."); +}); + +console.log("another log..."); +``` + +Provided the request to the remote film API has succeeded, then the function passed to `then` - `runOnFulfilment` will be executed. +However, as it is asynchronous, other parts of the program will run. To illustrate this, when the code above runs we will see the following logs: + +```console +another log... +running the callback function after fetch completes... +``` + +The function `runOnFulfilment` is defined earlier in the source code. However, we're not in charge of calling it. Instead this function is only called diff --git a/content/js3/blocks/chaining/index.md b/content/js3/blocks/chaining/index.md new file mode 100644 index 000000000..bd222e6ab --- /dev/null +++ b/content/js3/blocks/chaining/index.md @@ -0,0 +1,51 @@ ++++ +title = '🧱 Composing elements' +headless = true +time = 20 +facilitation = false +emoji= '🧩' +[objectives] + 1='Compose UI elements to some specification' + 2='Append DOM elements to other nodes in the DOM tree' ++++ + +We can start by calling `createElement` to create and {{}}To **compose DOM elements** means to **combine DOM elements** to form some part of the user interface.{{}}. For now, we'll only consider rendering the `title` property from the `film` object: + +```js +const film = { + title: "Killing of Flower Moon", + director: "Martin Scorsese", + times: ["15:35"], + certificate: "15", + duration: 112, +}; + +const filmCard = document.createElement("section"); +filmCard.innerHTML = ` +

${film.title}

+`; +console.log(filmCard); +``` + +If we open up the console tab, we should be able to see this element logged in the console. However, it won't yet appear in the browser. + +### Appending elements + +To display the film card, we need to append it to another element that is already in the DOM tree. + +```js {linenos=table,hl_lines=["14"],linenostart=1} +const film = { + title: "Killing of Flower Moon", + director: "Martin Scorsese", + times: ["15:35"], + certificate: "15", + duration: 112, +}; + +const filmCard = document.createElement("section"); +filmCard.innerHTML = ` +

${film.title}

+`; + +document.querySelector("ul").append(section); +``` diff --git a/content/js3/blocks/fetch/index.md b/content/js3/blocks/fetch/index.md new file mode 100644 index 000000000..5742fea79 --- /dev/null +++ b/content/js3/blocks/fetch/index.md @@ -0,0 +1,29 @@ ++++ +title = 'fetch API' +headless = true +time = 20 +facilitation = false +emoji= '🧩' +[objectives] ++++ + +Let's suppose we have a remote API hosted at the following url: "https://api-film-data.com". + +We can use applications like Postman to make requests to APIs. However, we want to make a request for the film data using JavaScript. We can use `fetch` to make network requests in JavaScript. Let's take a look at how we can do this: + +```js +const filmData = fetch("https://api-film-data.com/films"); +``` + +`fetch` is a JavaScript function. We call `fetch` using the url of the remote API we wish to fetch data from. Once `fetch` has got the data then we want to store it in a variable so we can then use it in our application. Let's log this data: + +```js +const filmData = fetch("https://api-film-data.com/films"); +console.log(filmData); +``` + +However, if we log this variable we don't get an array of data. We get: + +```console +Promise +``` diff --git a/content/js3/blocks/fetching-data/index.md b/content/js3/blocks/fetching-data/index.md new file mode 100644 index 000000000..a315a4c17 --- /dev/null +++ b/content/js3/blocks/fetching-data/index.md @@ -0,0 +1,23 @@ ++++ +title = 'Fetching data' +headless = true +time = 20 +facilitation = false +emoji= '🧩' +[objectives] + 1='Update a problem statement using web APIs to fetch data' ++++ + +If we start with some data like an array then we can render it in the user interface. However, it will be more typical for us to fetch data across a network and then display it in a browser. In other words, we'll have to request some data from a server and then render it in the user interface. To access data across a network, we'll make use of **web APIs**. + +Let's revisit a previous problem: + +> _Given_ a list of film data +> _When_ the page first loads +> _Then_ it should display the list of films now showing, including the film title, times and film certificate + +Now instead of starting with a list of film data, we'll have to fetch this list of film data from a remote API. We can restate the problem as follows: + +> _Given_ a **web API that serves** film data +> _When_ the page first loads +> _Then_ it should request and display the list of film data, including the film title, times and film certificate diff --git a/content/js3/blocks/internet/index.md b/content/js3/blocks/internet/index.md new file mode 100644 index 000000000..b7cd1a0d5 --- /dev/null +++ b/content/js3/blocks/internet/index.md @@ -0,0 +1,26 @@ ++++ +title = 'How the internet works' +headless = true +time = 20 +facilitation = false +emoji= '🧩' +[objectives] + 1='Describe what happens when a user enters a url into a browser' + 2='Explain the purpose of the HTTP protocol' + 3='Define a GET request in the HTTP protocol' ++++ + +Now we'll need to make use of the internet in order t + +{{}} +{{}} +{{}}https://www.youtube.com/watch?v=Dxcc6ycZ73M +{{}} +{{}} +{{}} +{{}}https://www.youtube.com/watch?v=ZhEf7e4kopM{{}} +{{}} +{{}} +{{}}https://www.youtube.com/watch?v=kBXQZMmiA4s{{}} +{{}} +{{}} diff --git a/content/js3/blocks/using-fetch/index.md b/content/js3/blocks/using-fetch/index.md new file mode 100644 index 000000000..e9199023e --- /dev/null +++ b/content/js3/blocks/using-fetch/index.md @@ -0,0 +1,26 @@ ++++ +title = 'Requesting from a remote API' +headless = true +time = 20 +facilitation = false +emoji= '🧩' +[objectives] ++++ + +Let's suppose we have a remote API hosted at the following url: "https://api-film-data.com". + +As we're trying to access film data this API will make film data available on a particular endpoint. IN reality, we would check the documentation to discover information about such an endpoint but we can assume we're working with a **`/films` endpoint**. This means if we make a HTTP GET request to this endpoint then we can get access some film data. + +We can make a request to a remote API in several different ways. First off, we can make a request to an API using an application like Postman. Postman is a rest client: it is an application that enables users to make a request. + +{{}} +{{}} + +1. Download the [Postman application](https://www.postman.com/downloads/) if you've not done so already + +2. Identify a web API from this [list of public APIs](https://github.com/public-apis/public-apis). In most cases, you'll also need to obtain an API key to make use of their API. + +3. Make a GET request to one of the endpoints and check you can see a valid response. + +{{}} +{{}} diff --git a/content/js3/sprints/2/prep/index.md b/content/js3/sprints/2/prep/index.md index 250bc0cfd..b78d80511 100644 --- a/content/js3/sprints/2/prep/index.md +++ b/content/js3/sprints/2/prep/index.md @@ -7,8 +7,18 @@ weight = 1 backlog= 'Module-JS3' backlog_filter= 'Week 2' [[blocks]] +name="Fetching data" +src="js3/blocks/fetching-data" +[[blocks]] +name="How the internet works" +src="js3/blocks/internet" +[[blocks]] +name="Using fetch" +src="js3/blocks/using-fetch" +[[blocks]] +name="Asynchronicity" +src="js3/blocks/asynchronicity" +[[blocks]] name= "Gathering requirements Prep" src="https://cyf-pd.netlify.app/blocks/gathering-requirements-prep/readme/" +++ - - From dfb5df286cf0d584ed3cea71681d66504d49c0fd Mon Sep 17 00:00:00 2001 From: Dedekind561 Date: Tue, 28 Nov 2023 09:11:31 +0000 Subject: [PATCH 02/12] remove old content from chaining block --- content/js3/blocks/chaining/index.md | 45 +--------------------------- 1 file changed, 1 insertion(+), 44 deletions(-) diff --git a/content/js3/blocks/chaining/index.md b/content/js3/blocks/chaining/index.md index bd222e6ab..07b47ff8e 100644 --- a/content/js3/blocks/chaining/index.md +++ b/content/js3/blocks/chaining/index.md @@ -1,51 +1,8 @@ +++ -title = '🧱 Composing elements' +title = 'Chaining' headless = true time = 20 facilitation = false emoji= '🧩' [objectives] - 1='Compose UI elements to some specification' - 2='Append DOM elements to other nodes in the DOM tree' +++ - -We can start by calling `createElement` to create and {{}}To **compose DOM elements** means to **combine DOM elements** to form some part of the user interface.{{}}. For now, we'll only consider rendering the `title` property from the `film` object: - -```js -const film = { - title: "Killing of Flower Moon", - director: "Martin Scorsese", - times: ["15:35"], - certificate: "15", - duration: 112, -}; - -const filmCard = document.createElement("section"); -filmCard.innerHTML = ` -

${film.title}

-`; -console.log(filmCard); -``` - -If we open up the console tab, we should be able to see this element logged in the console. However, it won't yet appear in the browser. - -### Appending elements - -To display the film card, we need to append it to another element that is already in the DOM tree. - -```js {linenos=table,hl_lines=["14"],linenostart=1} -const film = { - title: "Killing of Flower Moon", - director: "Martin Scorsese", - times: ["15:35"], - certificate: "15", - duration: 112, -}; - -const filmCard = document.createElement("section"); -filmCard.innerHTML = ` -

${film.title}

-`; - -document.querySelector("ul").append(section); -``` From 751d531e0df241bc48bdad6b4a6cd20d623810c7 Mon Sep 17 00:00:00 2001 From: Sally McGrath Date: Thu, 30 Nov 2023 21:07:05 +0000 Subject: [PATCH 03/12] increase timings I think that's all we can reasonably do. I feel overloaded just writing it. Next week we can do sequencing, async/await etc --- content/js3/blocks/asynchronicity/index.md | 76 ------ content/js3/blocks/asynchrony/index.md | 68 ++++++ content/js3/blocks/callbacks/index.md | 54 +++++ content/js3/blocks/chaining/index.md | 2 +- content/js3/blocks/fetching-data/index.md | 59 ++++- content/js3/blocks/internet/index.md | 2 +- content/js3/blocks/latency/index.md | 21 ++ content/js3/blocks/promises/index.md | 9 + content/js3/blocks/then/index.md | 9 + content/js3/blocks/using-fetch/index.md | 48 +++- content/js3/prep/index.md | 5 +- content/js3/sprints/3/prep/index.md | 19 +- static/dummy-apis/films.json | 269 +++++++++++++++++++++ 13 files changed, 537 insertions(+), 104 deletions(-) delete mode 100644 content/js3/blocks/asynchronicity/index.md create mode 100644 content/js3/blocks/asynchrony/index.md create mode 100644 content/js3/blocks/callbacks/index.md create mode 100644 content/js3/blocks/latency/index.md create mode 100644 content/js3/blocks/promises/index.md create mode 100644 content/js3/blocks/then/index.md create mode 100644 static/dummy-apis/films.json diff --git a/content/js3/blocks/asynchronicity/index.md b/content/js3/blocks/asynchronicity/index.md deleted file mode 100644 index 1db171e03..000000000 --- a/content/js3/blocks/asynchronicity/index.md +++ /dev/null @@ -1,76 +0,0 @@ -+++ -title = 'Asynchronicity' -headless = true -time = 20 -facilitation = false -emoji= '🧩' -[objectives] -+++ - -We can call functions and can store their return values in variables. However, storing the return value of `fetch` doesn't give us direct access to the film data that we need. - -```js -const filmData = fetch("https://api-film-data.com/films"); -console.log(filmData); // filmData not available here -``` - -`fetch `is an **asynchronous** function. `fetch` needs to request information across a network and requests like this take time. The length of time for the request to finish depends on lots of external factors such as how fast the external server processes our request. Such factors are beyond our control. When `fetch` is called, we still need other parts of our program. We cannot wait around for a network request to finish before we start handling other tasks in our application. To handle this asynchronicity, we can use {{}}A **Promise** is a JavaScript object that enables us to access the eventual outcome of an asynchronous task{{}}. - -### Promise object - -Promise objects are in one of three different states: - -- **pending** - this means the asynchronous task is waiting / not completed -- **fulfilled** - the async task succeeded -- **rejection** - the async task failed - -### On fulfilment - -Let's consider our example again: - -```js -fetch("https://api-film-data.com/films"); // this is a Promise object -``` - -`fetch` **returns** a Promise object. When the Promise is first created, its state will be **pending** ( as the network request hasn't completed ). - -> πŸ’‘ However, we'll need to execute some code when if the async task is successful. In other words, we'll need to execute some code when the Promise state moves from **pending** -> **fulfilled**. - -To run some code when the network request is successful, we can use a special function called `then` available on the Promise object. `then` takes a function as an argument that is called automatically once the Promise's state is fulfilled. - -```js -fetch("https://api-film-data.com/films").then(function runOnFulfilment(data) { - console.log(data); -}); - -console.log("another log..."); -``` - -Let's break down what's happening here. -`then` is passed a callback function defined as `runOnFulfilment`: - -```js -function runOnFulfilment(data) { - console.log(data); -} -``` - -We're also logging outside of this function too: - -```js {linenos=table,hl_lines=["5"],linenostart=1} -fetch("https://api-film-data.com/films").then(function runOnFulfilment(data) { - console.log("running the callback function after fetch completes..."); -}); - -console.log("another log..."); -``` - -Provided the request to the remote film API has succeeded, then the function passed to `then` - `runOnFulfilment` will be executed. -However, as it is asynchronous, other parts of the program will run. To illustrate this, when the code above runs we will see the following logs: - -```console -another log... -running the callback function after fetch completes... -``` - -The function `runOnFulfilment` is defined earlier in the source code. However, we're not in charge of calling it. Instead this function is only called diff --git a/content/js3/blocks/asynchrony/index.md b/content/js3/blocks/asynchrony/index.md new file mode 100644 index 000000000..ba284a151 --- /dev/null +++ b/content/js3/blocks/asynchrony/index.md @@ -0,0 +1,68 @@ ++++ +title = '⏳ Asynchrony : outside time' +headless = true +time = 30 +facilitation = false +emoji= '🧩' +[objectives] ++++ + +We can handle latency using {{}}run code in a different order.{{}} To understand asynchrony we first need to be clear about {{}}run code in the order it is written.{{}}. + +We have written a lot of JavaScript programs that execute sequentially. This means that each line of code is run in order, one after the other. +{{}} + +#### For example: + +```js +console.log("first"); +console.log("second"); +console.log("third"); +``` + +<---> + +#### Outputs: + +```console +first +second +third +``` + +{{}} +Each line of code is run in order. This is synchronous execution. We do this because JavaScript is {{}} +A single thread can do one thing at a time. JavaScript is a single threaded language. +{{}}. + +When we call a function, the function will run to completion before the next line of code is executed. But what if we need to wait for something to happen? What if we need to wait for our data to arrive before we can show it? In this case, we can use asynchronous execution. + +{{}} +{{}} +We have already used asynchronous execution. We have defined eventListeners that _listen_ for events to happen, _then_ execute a callback function. But here's a new idea: eventListeners are part of the [Event API](https://developer.mozilla.org/en-US/docs/Web/API/Event). They are not part of JavaScript! 🀯 + +When you set an eventListener you are really sending a call to a Web API and asking it do something for you. + +```js +const search = document.getElementById("search"); +const waitForEvent = search.addEventListener("input", handleInput); +``` + +The callback `handleInput` cannot run until the user types. With `fetch`, the callback function cannot run until the data arrives. In both cases, we are waiting for something to happen before we can run our code. +{{}} +{{}} + + +{{}} +{{}} + +```mermaid +graph LR + TimeProblem[πŸ—“οΈ Time Problem] --> |caused by| SingleThread[🧡 Single thread] + SingleThread --> |send tasks to| ClientAPIs + TimeProblem --> |solved by| Asynchrony[πŸ›ŽοΈ Asynchrony] + Asynchrony --> | delivered with | ClientAPIs{πŸ’» Client APIs} + ClientAPIs --> |like| setTimeout[(⏲️ setTimeout)] + ClientAPIs --> |like| eventListener[(🦻🏾 eventListener)] + ClientAPIs --> |like| fetch[(πŸ• fetch)] +``` diff --git a/content/js3/blocks/callbacks/index.md b/content/js3/blocks/callbacks/index.md new file mode 100644 index 000000000..ebd3e41e5 --- /dev/null +++ b/content/js3/blocks/callbacks/index.md @@ -0,0 +1,54 @@ ++++ +title = 'πŸͺƒ Callbacks' +headless = true +time = 20 +facilitation = false +emoji= '🧩' +[objectives] ++++ + +Consider this visualisation of an asynchronous program: + + + +When we call [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) we send **a function call** to a client side Web API. The code isn't executing in our single thread any more, so we can run the next line. The countdown _is_ happening, but it's not happening _in our thread_. + +When the time runs out, our Web API sends a message to our program to let us know. This is called an {{}}An event is a signal that something has happened.{{}}. Our API sends its message to our {{}}The event loop is a JavaScript mechanism that handles asynchronous callbacks.{{}}. And what message does the event loop send? It sends a **callback**. It sends _our_ call _back_. + +{{}} +A callback is our function call, sent back to us through the event loop. +{{}} + +{{}} +{{}} +**With a pen and paper**, draw a diagram of your mental model of the event loop. + +Use your model to predict the order of logged numbers in the following code snippet: + +```js +setTimeout(function timeout() { + console.log("1"); +}, 2000); +setTimeout(function timeout() { + console.log("2"); +}, 500); +setTimeout(function timeout() { + console.log("3"); +}, 0); +``` + +{{}} +{{}} + +```mermaid +graph + Callbacks{{πŸͺƒ Callbacks}} --> |run on| SingleThread[🧡 Single thread] + SingleThread --> |handled by| EventLoop[πŸ” Event Loop] + EventLoop --> |queues| Callbacks + SingleThread --> |send tasks to| ClientAPIs{πŸ’» Client APIs} + ClientAPIs --> | send| Callbacks +``` + +Did yours look different? There are many ways to visualise the event loop. Work on building your own mental model that helps you predict how code will run. +{{}} +{{}} diff --git a/content/js3/blocks/chaining/index.md b/content/js3/blocks/chaining/index.md index 07b47ff8e..d2ed047f7 100644 --- a/content/js3/blocks/chaining/index.md +++ b/content/js3/blocks/chaining/index.md @@ -1,5 +1,5 @@ +++ -title = 'Chaining' +title = 'Chaining Promises' headless = true time = 20 facilitation = false diff --git a/content/js3/blocks/fetching-data/index.md b/content/js3/blocks/fetching-data/index.md index a315a4c17..67d90f3de 100644 --- a/content/js3/blocks/fetching-data/index.md +++ b/content/js3/blocks/fetching-data/index.md @@ -1,5 +1,5 @@ +++ -title = 'Fetching data' +title = 'πŸ• Fetching data' headless = true time = 20 facilitation = false @@ -8,16 +8,55 @@ emoji= '🧩' 1='Update a problem statement using web APIs to fetch data' +++ -If we start with some data like an array then we can render it in the user interface. However, it will be more typical for us to fetch data across a network and then display it in a browser. In other words, we'll have to request some data from a server and then render it in the user interface. To access data across a network, we'll make use of **web APIs**. +So far we have displayed films data stored in our JavaScript code. But real applications fetch data from servers over the internet. We can restate our problem as follows: -Let's revisit a previous problem: - -> _Given_ a list of film data +> _Given_ a **web API that serves** film data > _When_ the page first loads -> _Then_ it should display the list of films now showing, including the film title, times and film certificate +> _Then_ the page should fetch and display the list of film data, including the film title, times and film certificate -Now instead of starting with a list of film data, we'll have to fetch this list of film data from a remote API. We can restate the problem as follows: +We will use [`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch), a {{}} +A client side Web API lives in the browser. They provide programmatic access _to_ built-in browser functions _from_ JavaScript. {{}}. Fetch will fetch our data from the {{}} +A server side Web API lives on a server. They provide programmatic access _to_ data or functions stored on the server _from_ JavaScript. {{}}. -> _Given_ a **web API that serves** film data -> _When_ the page first loads -> _Then_ it should request and display the list of film data, including the film title, times and film certificate +_Using_ fetch is simple. But we want to understand what is happening more completely. So let's take ourselves on a journey through time. + +
+πŸ‘‰πŸΎ Unfurl to see the journey + +```mermaid +graph TD + fetch[(πŸ• fetch)] --> |sends a| Request{πŸ“€ Request} + Request --> |has a latency| TimeProblem[πŸ—“οΈ Time Problem] + Request --> |to| ServerAPIs + fetch --> |is a| ClientAPIs + + TimeProblem --> |caused by| SingleThread[🧡 Single thread] + Callbacks{{πŸͺƒ Callbacks}} --> |run on| SingleThread + SingleThread --> |handled by| EventLoop[πŸ” Event Loop] + EventLoop --> |queues| Callbacks + SingleThread --> |send tasks to| ClientAPIs + SingleThread --> |handled by| Asynchrony + + TimeProblem --> |solved by| Asynchrony[πŸ›ŽοΈ Asynchrony] + Asynchrony --> |delivered with| Promise{{🀝 Promises}} + Asynchrony --> | delivered with | ClientAPIs + Promise --> |resolve to a| Response{πŸ“€ Response} + Promise --> |join the| EventLoop{{Event Loop πŸ”}} + Promise --> |syntax| async{{πŸƒβ€β™‚οΈ async}} + async --> |syntax| await{{πŸ“­ await}} + await --> |resolves to| Response + Response ---> |sequence with| then{{βœ”οΈ then}} + + + WebAPIs((🧰 Web APIs)) --> |live in your browser| ClientAPIs{πŸ’» Client side APIs} + ClientAPIs --> |like| setTimeout[(⏲️ setTimeout)] + ClientAPIs --> |like| eventListener[(🦻🏾 eventListener)] + WebAPIs --> |live on the internet| ServerAPIs{🌐 Server side APIs} + ServerAPIs --> |serve our| Data[(πŸ’Ύ Data)] + Data --> |as a| Response + +``` + +πŸ˜΅β€πŸ’« This is a lot to take in. Let's break it down and make sense of it. + +
diff --git a/content/js3/blocks/internet/index.md b/content/js3/blocks/internet/index.md index b7cd1a0d5..8f899507b 100644 --- a/content/js3/blocks/internet/index.md +++ b/content/js3/blocks/internet/index.md @@ -10,7 +10,7 @@ emoji= '🧩' 3='Define a GET request in the HTTP protocol' +++ -Now we'll need to make use of the internet in order t +We've been using the internet for years, but how does it actually work? What happens when you type a URL into a browser? How does the browser know where to go? How does it know what to show? How does it know how to show it? {{}} {{}} diff --git a/content/js3/blocks/latency/index.md b/content/js3/blocks/latency/index.md new file mode 100644 index 000000000..c9acaa126 --- /dev/null +++ b/content/js3/blocks/latency/index.md @@ -0,0 +1,21 @@ ++++ +title = 'πŸ—“οΈ Latency' +headless = true +time = 5 +facilitation = false +emoji= '🧩' +[objectives] + 1='Define latency' ++++ + +```mermaid +graph LR + fetch[(πŸ• fetch)] --> |sends a| Request{πŸ“€ Request} + Request --> |has a latency| TimeProblem[πŸ—“οΈ Time Problem] +``` + +Once we are taking our data on a journey over a network, we introduce the problem of latency. Latency is the time taken for a request to traverse the network. + +> πŸ’‘ Network latency is travel time. + +Why is latency a problem? Because it means we need to **wait** for our data. But if we stopped our program to wait for data, then we wouldn't be able to do anything else. We need to handle this time problem. Programming often involves time problems, and latency is just one of them. diff --git a/content/js3/blocks/promises/index.md b/content/js3/blocks/promises/index.md new file mode 100644 index 000000000..56bfa7cbf --- /dev/null +++ b/content/js3/blocks/promises/index.md @@ -0,0 +1,9 @@ ++++ +title = 'What is a Promise?' +headless = true +time = 30 +facilitation = false +emoji= '🧩' +[objectives] + 1='' ++++ diff --git a/content/js3/blocks/then/index.md b/content/js3/blocks/then/index.md new file mode 100644 index 000000000..0e3ae14e7 --- /dev/null +++ b/content/js3/blocks/then/index.md @@ -0,0 +1,9 @@ ++++ +title = 'Making sense of .then()' +headless = true +time = 30 +facilitation = false +emoji= '🧩' +[objectives] + 1='' ++++ diff --git a/content/js3/blocks/using-fetch/index.md b/content/js3/blocks/using-fetch/index.md index e9199023e..e6c6301c9 100644 --- a/content/js3/blocks/using-fetch/index.md +++ b/content/js3/blocks/using-fetch/index.md @@ -1,26 +1,52 @@ +++ -title = 'Requesting from a remote API' +title = '🌐 Requesting from a server side API' headless = true time = 20 facilitation = false emoji= '🧩' [objectives] +1="Fetch data from a server side API" + +++ -Let's suppose we have a remote API hosted at the following url: "https://api-film-data.com". +So now we have these pieces of our giant concept map + +πŸ—“οΈ we know that sending πŸ“€ requests over a network takes time +🧡 we know that we should not stop our program to wait for data +πŸ“€ we know that we can send a request using `fetch()` +πŸ• we know that `fetch` is a πŸ’» client side 🧰 Web API +πŸ«±πŸΏβ€πŸ«²πŸ½ we know that `fetch` returns a `Promise`? (...this last one is pending) + +But we still don't know how to use `fetch` to get data from a server side API. Let's find out. Run this code in the console in your browser. -As we're trying to access film data this API will make film data available on a particular endpoint. IN reality, we would check the documentation to discover information about such an endpoint but we can assume we're working with a **`/films` endpoint**. This means if we make a HTTP GET request to this endpoint then we can get access some film data. +```js +const endpoint = "//curriculum.codeyourfuture.io/dummy-apis/films.json"; +const fetchPromise = fetch(endpoint); +fetchPromise.then((response) => { + console.log(response.json()); +}); +``` -We can make a request to a remote API in several different ways. First off, we can make a request to an API using an application like Postman. Postman is a rest client: it is an application that enables users to make a request. +So that's how we use `fetch` to get data from a server side API. In [our filterFilms code](https://curriculum.codeyourfuture.io/filterfilms), we can replace the films array with the data fetched from the server. -{{}} -{{}} +```js +// Begin with an empty state +const state = { + films: [], +}; +// Data +const endpoint = "//curriculum.codeyourfuture.io/dummy-apis/films.json"; -1. Download the [Postman application](https://www.postman.com/downloads/) if you've not done so already +const fetchFilms = async () => { + const response = await fetch(endpoint); + return await response.json(); +}; // our async function returns a Promise -2. Identify a web API from this [list of public APIs](https://github.com/public-apis/public-apis). In most cases, you'll also need to obtain an API key to make use of their API. +fetchFilms().then((films) => { + render(filmContainer, films); // when +}); +``` -3. Make a GET request to one of the endpoints and check you can see a valid response. +πŸ• `fetch` returns a πŸ«±πŸΏβ€πŸ«²πŸ½ ‍`Promise`; the πŸ«±πŸΏβ€πŸ«²πŸ½ `Promise` fulfils itself with a πŸ“₯ response; the response contains our πŸ’Ύ data. -{{}} -{{}} +We will dig into this syntax: `Promises`, `async`, `await`, and `then` in our next sprint and complete our concept map. diff --git a/content/js3/prep/index.md b/content/js3/prep/index.md index 8ed4f8196..0626c2b4f 100644 --- a/content/js3/prep/index.md +++ b/content/js3/prep/index.md @@ -6,6 +6,7 @@ emoji= 'πŸ“' menu_level = ['module'] weight = 1 backlog= 'Module-JS3' +[[blocks]] +name="How the internet works" +src="js3/blocks/internet" +++ - - diff --git a/content/js3/sprints/3/prep/index.md b/content/js3/sprints/3/prep/index.md index 1ff904e72..9b95ddaf3 100644 --- a/content/js3/sprints/3/prep/index.md +++ b/content/js3/sprints/3/prep/index.md @@ -7,8 +7,21 @@ weight = 1 backlog= 'Module-JS3' backlog_filter= 'Week 3' [[blocks]] -name="Produt MVP and features" +name="Fetching data" +src="js3/blocks/fetching-data" +[[blocks]] +name="Latency" +src="js3/blocks/latency" +[[blocks]] +name="Asynchrony" +src="js3/blocks/asynchrony" +[[blocks]] +name="Callbacks" +src="js3/blocks/callbacks" +[[blocks]] +name="Using .fetch()" +src="js3/blocks/using-fetch" +[[blocks]] +name="Product MVP and features" src="https://cyf-pd.netlify.app/blocks/define-your-products-mvp/readme/" +++ - - diff --git a/static/dummy-apis/films.json b/static/dummy-apis/films.json new file mode 100644 index 000000000..4f2f8c441 --- /dev/null +++ b/static/dummy-apis/films.json @@ -0,0 +1,269 @@ +[ + { + "title": "Killing of Flower Moon", + "director": "Martin Scorsese", + "times": ["15:35"], + "certificate": "15", + "duration": 112 + }, + { + "title": "Typist Artist Pirate King", + "directory": "Carol Morley", + "times": ["15:00", "20:00"], + "certificate": "12A", + "duration": 108 + }, + { + "title": "The Souvenir", + "directory": "Joanna Hogg", + "times": ["18:00"], + "certificate": "15", + "duration": 119 + }, + { + "title": "The White Crow", + "directory": "Ralph Fiennes", + "times": ["20:30"], + "certificate": "12A", + "duration": 127 + }, + { + "title": "The Prisoner of Azkaban", + "directory": "Alfonso CuarΓ³n", + "times": ["15:00"], + "certificate": "PG", + "duration": 142 + }, + { + "title": "The Chamber of Secrets", + "directory": "Chris Columbus", + "times": ["18:00"], + "certificate": "PG", + "duration": 161 + }, + { + "title": "The Philosopher's Stone", + "directory": "Chris Columbus", + "times": ["20:30"], + "certificate": "PG", + "duration": 152 + }, + + { + "title": "The Philosopher's Stone", + "directory": "Chris Columbus", + "times": ["20:30"], + "certificate": "PG", + "duration": 152 + }, + { + "title": "The Chamber of Secrets", + "directory": "Chris Columbus", + "times": ["18:00"], + "certificate": "PG", + "duration": 161 + }, + { + "title": "The Prisoner of Azkaban", + "directory": "Alfonso CuarΓ³n", + "times": ["15:00"], + "certificate": "PG", + "duration": 142 + }, + { + "title": "The Goblet of Fire", + "directory": "Mike Newell", + "times": ["20:30"], + "certificate": "12A", + "duration": 157 + }, + { + "title": "The Order of the Phoenix", + "directory": "David Yates", + "times": ["15:00"], + "certificate": "12A", + "duration": 138 + }, + { + "title": "The Half-Blood Prince", + "directory": "David Yates", + "times": ["18:00"], + "certificate": "12A", + "duration": 153 + }, + { + "title": "The Deathly Hallows Part 1", + "directory": "David Yates", + "times": ["20:30"], + "certificate": "12A", + "duration": 146 + }, + { + "title": "The Deathly Hallows Part 2", + "directory": "David Yates", + "times": ["15:00"], + "certificate": "12A", + "duration": 130 + }, + { + "title": "The Goblet of Fire", + "directory": "Mike Newell", + "times": ["20:30"], + "certificate": "12A", + "duration": 157 + }, + { + "title": "The Order of the Phoenix", + "directory": "David Yates", + "times": ["15:00"], + "certificate": "12A", + "duration": 138 + }, + { + "title": "The Half-Blood Prince", + "directory": "David Yates", + "times": ["18:00"], + "certificate": "12A", + "duration": 153 + }, + { + "title": "Star Trek IV: The Voyage Home", + "directory": "Leonard Nimoy", + "times": ["20:30"], + "certificate": "12A", + "duration": 119 + }, + { + "title": "Star Trek V: The Final Frontier", + "directory": "William Shatner", + "times": ["15:00"], + "certificate": "12A", + "duration": 107 + }, + { + "title": "Star Trek VI: The Undiscovered Country", + "directory": "Nicholas Meyer", + "times": ["18:00"], + "certificate": "12A", + "duration": 109 + }, + { + "title": "Star Trek: Generations", + "directory": "David Carson", + "times": ["20:30"], + "certificate": "12A", + "duration": 118 + }, + { + "title": "Star Trek: First Contact", + "directory": "Jonathan Frakes", + "times": ["15:00"], + "certificate": "12A", + "duration": 111 + }, + { + "title": "Star Trek: Insurrection", + "directory": "Jonathan Frakes", + "times": ["18:00"], + "certificate": "12A", + "duration": 103 + }, + { + "title": "Star Trek: Nemesis", + "directory": "Stuart Baird", + "times": ["20:30"], + "certificate": "12A", + "duration": 116 + }, + { + "title": "Star Trek", + "directory": "J. J. Abrams", + "times": ["15:00"], + "certificate": "12A", + "duration": 127 + }, + { + "title": "Star Trek Into Darkness", + "directory": "J. J. Abrams", + "times": ["18:00"], + "certificate": "12A", + "duration": 132 + }, + { + "title": "Star Trek Beyond", + "directory": "Justin Lin", + "times": ["20:30"], + "certificate": "12A", + "duration": 122 + }, + { + "title": "The Wrath of Khan", + "directory": "Nicholas Meyer", + "times": ["15:00"], + "certificate": "12A", + "duration": 113 + }, + { + "title": "The Search for Spock", + "directory": "Leonard Nimoy", + "times": ["18:00"], + "certificate": "12A", + "duration": 105 + }, + { + "title": "The Voyage Home", + "directory": "Leonard Nimoy", + "times": ["20:30"], + "certificate": "12A", + "duration": 119 + }, + { + "title": "The Final Frontier", + "directory": "William Shatner", + "times": ["15:00"], + "certificate": "12A", + "duration": 107 + }, + { + "title": "The Undiscovered Country", + "directory": "Nicholas Meyer", + "times": ["18:00"], + "certificate": "12A", + "duration": 109 + }, + { + "title": "Generations", + "directory": "David Carson", + "times": ["20:30"], + "certificate": "12A", + "duration": 118 + }, + { + "title": "First Contact", + "directory": "Jonathan Frakes", + "times": ["15:00"], + "certificate": "12A", + "duration": 111 + }, + { + "title": "Insurrection", + "directory": "Jonathan Frakes", + "times": ["18:00"], + "certificate": "12A", + "duration": 103 + }, + { + "title": "Nemesis", + "directory": "Stuart Baird", + "times": ["20:30"], + "certificate": "12A", + "duration": 116 + }, + { + "title": "Star Trek", + "directory": "J. J. Abrams", + "times": ["15:00"], + "certificate": "12A", + "duration": 127 + } +] From 98a97384db3cbe27e84d7290431f28e653fcc3bc Mon Sep 17 00:00:00 2001 From: Sally McGrath Date: Thu, 30 Nov 2023 21:20:05 +0000 Subject: [PATCH 04/12] columns shortcode --- assets/styles/04-components/columns.scss | 7 +++++++ layouts/shortcodes/columns.html | 8 ++++++++ 2 files changed, 15 insertions(+) create mode 100644 assets/styles/04-components/columns.scss create mode 100644 layouts/shortcodes/columns.html diff --git a/assets/styles/04-components/columns.scss b/assets/styles/04-components/columns.scss new file mode 100644 index 000000000..978b66ab7 --- /dev/null +++ b/assets/styles/04-components/columns.scss @@ -0,0 +1,7 @@ +// put anything side by side + +.c-columns { + display: grid; + gap: var(--theme-spacing--gutter); + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); +} diff --git a/layouts/shortcodes/columns.html b/layouts/shortcodes/columns.html new file mode 100644 index 000000000..2188e92cf --- /dev/null +++ b/layouts/shortcodes/columns.html @@ -0,0 +1,8 @@ +
+ {{ $cols := split .Inner "<--->" }} + {{ range $cols }} +
+ {{ . | safeHTML | markdownify }} +
+ {{ end }} +
From 9afe8d76675a519489fa10cb2713d948668c6799 Mon Sep 17 00:00:00 2001 From: Sally McGrath Date: Thu, 30 Nov 2023 21:55:47 +0000 Subject: [PATCH 05/12] missing learning objectives --- content/js3/blocks/asynchrony/index.md | 3 +++ content/js3/blocks/callbacks/index.md | 3 +++ content/js3/blocks/using-fetch/index.md | 5 +++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/content/js3/blocks/asynchrony/index.md b/content/js3/blocks/asynchrony/index.md index ba284a151..f756e7251 100644 --- a/content/js3/blocks/asynchrony/index.md +++ b/content/js3/blocks/asynchrony/index.md @@ -5,6 +5,9 @@ time = 30 facilitation = false emoji= '🧩' [objectives] +1="Define asynchrony" +2="Explain why we need asynchrony" +3="Identify an asynchronous method we have already used" +++ We can handle latency using {{}}run code in a different order.{{}} To understand asynchrony we first need to be clear about {{}}run code in the order it is written.{{}}. diff --git a/content/js3/blocks/callbacks/index.md b/content/js3/blocks/callbacks/index.md index ebd3e41e5..8360b5322 100644 --- a/content/js3/blocks/callbacks/index.md +++ b/content/js3/blocks/callbacks/index.md @@ -5,6 +5,9 @@ time = 20 facilitation = false emoji= '🧩' [objectives] +1='Define a callback' +2="Sketch the event loop" +3="Predict the order of logged numbers using the event loop model" +++ Consider this visualisation of an asynchronous program: diff --git a/content/js3/blocks/using-fetch/index.md b/content/js3/blocks/using-fetch/index.md index e6c6301c9..bf00e5082 100644 --- a/content/js3/blocks/using-fetch/index.md +++ b/content/js3/blocks/using-fetch/index.md @@ -5,8 +5,9 @@ time = 20 facilitation = false emoji= '🧩' [objectives] -1="Fetch data from a server side API" - +1="List 4 preceding concepts of asynchronous programming in JavaScript" +2="Identify unknown concepts still to be learned" +3="Fetch data from a server side API" +++ So now we have these pieces of our giant concept map From 47b079537617c31cc7d0d3064a638743371c6f94 Mon Sep 17 00:00:00 2001 From: Daniel Wagner-Hall Date: Mon, 18 Dec 2023 21:37:45 +0000 Subject: [PATCH 06/12] Copy edits to JS3W3 --- content/js3/blocks/asynchrony/index.md | 6 ++++-- content/js3/blocks/callbacks/index.md | 4 ++-- content/js3/blocks/fetching-data/index.md | 8 ++++++-- content/js3/blocks/latency/index.md | 8 ++++++-- content/js3/blocks/using-fetch/index.md | 4 +++- 5 files changed, 21 insertions(+), 9 deletions(-) diff --git a/content/js3/blocks/asynchrony/index.md b/content/js3/blocks/asynchrony/index.md index f756e7251..5b8da35b6 100644 --- a/content/js3/blocks/asynchrony/index.md +++ b/content/js3/blocks/asynchrony/index.md @@ -42,16 +42,18 @@ When we call a function, the function will run to completion before the next lin {{}} {{}} -We have already used asynchronous execution. We have defined eventListeners that _listen_ for events to happen, _then_ execute a callback function. But here's a new idea: eventListeners are part of the [Event API](https://developer.mozilla.org/en-US/docs/Web/API/Event). They are not part of JavaScript! 🀯 +We have already used asynchronous execution. We have defined eventListeners that _listen_ for events to happen, _then_ execute a callback function. But here's a new idea: eventListeners are part of the [Event API](https://developer.mozilla.org/en-US/docs/Web/API/Event). They are not part of JavaScript! 🀯 This means you can't use them in a Node REPL, but they are implemented in web browsers. The core of JavaScript is the same everywhere, but different contexts may add extra APIs. When you set an eventListener you are really sending a call to a Web API and asking it do something for you. ```js const search = document.getElementById("search"); -const waitForEvent = search.addEventListener("input", handleInput); +search.addEventListener("input", handleInput); ``` The callback `handleInput` cannot run until the user types. With `fetch`, the callback function cannot run until the data arrives. In both cases, we are waiting for something to happen before we can run our code. + +We use a function as a way of wrapping up the code that needs to be run later on. This means we can tell the browser _what_ to do when we're done waiting. {{}} {{}} diff --git a/content/js3/blocks/callbacks/index.md b/content/js3/blocks/callbacks/index.md index 8360b5322..cd0295893 100644 --- a/content/js3/blocks/callbacks/index.md +++ b/content/js3/blocks/callbacks/index.md @@ -16,10 +16,10 @@ Consider this visualisation of an asynchronous program: When we call [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) we send **a function call** to a client side Web API. The code isn't executing in our single thread any more, so we can run the next line. The countdown _is_ happening, but it's not happening _in our thread_. -When the time runs out, our Web API sends a message to our program to let us know. This is called an {{}}An event is a signal that something has happened.{{}}. Our API sends its message to our {{}}The event loop is a JavaScript mechanism that handles asynchronous callbacks.{{}}. And what message does the event loop send? It sends a **callback**. It sends _our_ call _back_. +When the time runs out, our Web API sends a message to our program to let us know. This is called an {{}}An event is a signal that something has happened.{{}}. Our API sends its message to our {{}}The event loop is a JavaScript mechanism that handles asynchronous callbacks.{{}}. And what message does the event loop send? It sends a **callback**. It sends _our_ call _back_. It tells our thread to run the code in that function. {{}} -A callback is our function call, sent back to us through the event loop. +A callback is our function call, sent back to us through the event loop, for us to run. {{}} {{}} diff --git a/content/js3/blocks/fetching-data/index.md b/content/js3/blocks/fetching-data/index.md index 67d90f3de..c41606f45 100644 --- a/content/js3/blocks/fetching-data/index.md +++ b/content/js3/blocks/fetching-data/index.md @@ -8,7 +8,7 @@ emoji= '🧩' 1='Update a problem statement using web APIs to fetch data' +++ -So far we have displayed films data stored in our JavaScript code. But real applications fetch data from servers over the internet. We can restate our problem as follows: +So far we have displayed film data stored in our JavaScript code. But real applications fetch data from servers over the internet. We can restate our problem as follows: > _Given_ a **web API that serves** film data > _When_ the page first loads @@ -18,10 +18,14 @@ We will use [`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_A A client side Web API lives in the browser. They provide programmatic access _to_ built-in browser functions _from_ JavaScript. {{}}. Fetch will fetch our data from the {{}} A server side Web API lives on a server. They provide programmatic access _to_ data or functions stored on the server _from_ JavaScript. {{}}. +Web APIs are useful because they let us get information which we don't ourselves know. The information may change over time, and we don't need to update our application. When we ask for the information, the web API will tell us the latest version. + +We also don't need to know how the web API works in order to use it. It may be written in a different programming language. It may talk to other web APIs we don't know about. All we need to know is how to talk to it. + _Using_ fetch is simple. But we want to understand what is happening more completely. So let's take ourselves on a journey through time.
-πŸ‘‰πŸΎ Unfurl to see the journey +πŸ‘‰πŸΎ Unfurl to see the journey (we will explain this all below!) ```mermaid graph TD diff --git a/content/js3/blocks/latency/index.md b/content/js3/blocks/latency/index.md index c9acaa126..798161292 100644 --- a/content/js3/blocks/latency/index.md +++ b/content/js3/blocks/latency/index.md @@ -14,8 +14,12 @@ graph LR Request --> |has a latency| TimeProblem[πŸ—“οΈ Time Problem] ``` -Once we are taking our data on a journey over a network, we introduce the problem of latency. Latency is the time taken for a request to traverse the network. +Instead of already having our data, we are now sending a request over the network to another computer, and then waiting for that computer to send us a response back. + +Now that our data is going on a journey over a network, we introduce the problem of latency. + +Latency is the time taken for a request to traverse the network. > πŸ’‘ Network latency is travel time. -Why is latency a problem? Because it means we need to **wait** for our data. But if we stopped our program to wait for data, then we wouldn't be able to do anything else. We need to handle this time problem. Programming often involves time problems, and latency is just one of them. +Why is latency a problem? Because it means we need to **wait** for our data. But our program can only do one thing at a time - if we stopped our program to wait for data, then we wouldn't be able to do anything else. We need to handle this time problem. Programming often involves time problems, and latency is just one of them. diff --git a/content/js3/blocks/using-fetch/index.md b/content/js3/blocks/using-fetch/index.md index bf00e5082..b8504b492 100644 --- a/content/js3/blocks/using-fetch/index.md +++ b/content/js3/blocks/using-fetch/index.md @@ -23,11 +23,13 @@ But we still don't know how to use `fetch` to get data from a server side API. L ```js const endpoint = "//curriculum.codeyourfuture.io/dummy-apis/films.json"; const fetchPromise = fetch(endpoint); -fetchPromise.then((response) => { +const _ = fetchPromise.then((response) => { console.log(response.json()); }); ``` +In the console, you can see a `Promise` was logged. A `Promise` is a placeholder which contains some data, but where the data may not be known yet. If you expand the `PromiseResult`, you should see some data which was returned from a server. + So that's how we use `fetch` to get data from a server side API. In [our filterFilms code](https://curriculum.codeyourfuture.io/filterfilms), we can replace the films array with the data fetched from the server. ```js From 874aa93dc629cce4cab84ba928612ebb7985405d Mon Sep 17 00:00:00 2001 From: Sally McGrath Date: Fri, 22 Dec 2023 14:20:48 +0000 Subject: [PATCH 07/12] tweaks from review 1. update time of async 2. move blocks into en 3. clarify web api def 4. bold latency 5. clarify concept list 6. rm unused blocks --- .../{ => en}/js3/blocks/asynchrony/index.md | 6 +++--- .../{ => en}/js3/blocks/callbacks/index.md | 0 content/{ => en}/js3/blocks/chaining/index.md | 0 content/{ => en}/js3/blocks/fetch/index.md | 0 .../js3/blocks/fetching-data/index.md | 19 ++++++++++--------- content/{ => en}/js3/blocks/internet/index.md | 0 content/{ => en}/js3/blocks/latency/index.md | 8 ++++---- .../{ => en}/js3/blocks/using-fetch/index.md | 13 ++++++------- content/js3/blocks/promises/index.md | 9 --------- content/js3/blocks/then/index.md | 9 --------- 10 files changed, 23 insertions(+), 41 deletions(-) rename content/{ => en}/js3/blocks/asynchrony/index.md (82%) rename content/{ => en}/js3/blocks/callbacks/index.md (100%) rename content/{ => en}/js3/blocks/chaining/index.md (100%) rename content/{ => en}/js3/blocks/fetch/index.md (100%) rename content/{ => en}/js3/blocks/fetching-data/index.md (60%) rename content/{ => en}/js3/blocks/internet/index.md (100%) rename content/{ => en}/js3/blocks/latency/index.md (72%) rename content/{ => en}/js3/blocks/using-fetch/index.md (74%) delete mode 100644 content/js3/blocks/promises/index.md delete mode 100644 content/js3/blocks/then/index.md diff --git a/content/js3/blocks/asynchrony/index.md b/content/en/js3/blocks/asynchrony/index.md similarity index 82% rename from content/js3/blocks/asynchrony/index.md rename to content/en/js3/blocks/asynchrony/index.md index 5b8da35b6..14534269e 100644 --- a/content/js3/blocks/asynchrony/index.md +++ b/content/en/js3/blocks/asynchrony/index.md @@ -1,7 +1,7 @@ +++ title = '⏳ Asynchrony : outside time' headless = true -time = 30 +time = 40 facilitation = false emoji= '🧩' [objectives] @@ -38,11 +38,11 @@ Each line of code is run in order. This is synchronous execution. We do this bec A single thread can do one thing at a time. JavaScript is a single threaded language. {{}}. -When we call a function, the function will run to completion before the next line of code is executed. But what if we need to wait for something to happen? What if we need to wait for our data to arrive before we can show it? In this case, we can use asynchronous execution. +When we call a function, the function will run to completion before the next line of code is executed. But what if we need to wait for something to happen? What if we need to wait for our data to arrive before we can show it? In this case, we can use **asynchronous execution**. {{}} {{}} -We have already used asynchronous execution. We have defined eventListeners that _listen_ for events to happen, _then_ execute a callback function. But here's a new idea: eventListeners are part of the [Event API](https://developer.mozilla.org/en-US/docs/Web/API/Event). They are not part of JavaScript! 🀯 This means you can't use them in a Node REPL, but they are implemented in web browsers. The core of JavaScript is the same everywhere, but different contexts may add extra APIs. +We have already used asynchronous execution. We have defined `eventListener`s that _listen_ for events to happen, _then_ execute a callback function. But here's a new idea: eventListeners are part of the [Event API](https://developer.mozilla.org/en-US/docs/Web/API/Event). They are not part of JavaScript! 🀯 This means you can't use them in a Node REPL, but they are implemented in web browsers. The core of JavaScript is the same everywhere, but different contexts may add extra APIs. When you set an eventListener you are really sending a call to a Web API and asking it do something for you. diff --git a/content/js3/blocks/callbacks/index.md b/content/en/js3/blocks/callbacks/index.md similarity index 100% rename from content/js3/blocks/callbacks/index.md rename to content/en/js3/blocks/callbacks/index.md diff --git a/content/js3/blocks/chaining/index.md b/content/en/js3/blocks/chaining/index.md similarity index 100% rename from content/js3/blocks/chaining/index.md rename to content/en/js3/blocks/chaining/index.md diff --git a/content/js3/blocks/fetch/index.md b/content/en/js3/blocks/fetch/index.md similarity index 100% rename from content/js3/blocks/fetch/index.md rename to content/en/js3/blocks/fetch/index.md diff --git a/content/js3/blocks/fetching-data/index.md b/content/en/js3/blocks/fetching-data/index.md similarity index 60% rename from content/js3/blocks/fetching-data/index.md rename to content/en/js3/blocks/fetching-data/index.md index c41606f45..61add2a58 100644 --- a/content/js3/blocks/fetching-data/index.md +++ b/content/en/js3/blocks/fetching-data/index.md @@ -5,22 +5,23 @@ time = 20 facilitation = false emoji= '🧩' [objectives] - 1='Update a problem statement using web APIs to fetch data' + 1='Define a client side Web API' + 2='Define a server side API' +++ So far we have displayed film data stored in our JavaScript code. But real applications fetch data from servers over the internet. We can restate our problem as follows: -> _Given_ a **web API that serves** film data +> _Given_ an **API that serves** film data > _When_ the page first loads -> _Then_ the page should fetch and display the list of film data, including the film title, times and film certificate +> _Then_ the page should `fetch` and display the list of film data, including the film title, times and film certificate We will use [`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch), a {{}} -A client side Web API lives in the browser. They provide programmatic access _to_ built-in browser functions _from_ JavaScript. {{}}. Fetch will fetch our data from the {{}} -A server side Web API lives on a server. They provide programmatic access _to_ data or functions stored on the server _from_ JavaScript. {{}}. +A client side [Web API](https://developer.mozilla.org/en-US/docs/Web/API) lives in the browser. They provide programmatic access _to_ built-in browser functions _from_ JavaScript. {{}}. Fetch will fetch our data from the {{}} +A server side API lives on a server. They provide programmatic access _to_ data or functions stored on the server _from_ JavaScript. {{}}. -Web APIs are useful because they let us get information which we don't ourselves know. The information may change over time, and we don't need to update our application. When we ask for the information, the web API will tell us the latest version. +APIs are useful because they let us get information which we don't ourselves know. The information may change over time, and we don't need to update our application. When we ask for the information, the API will tell us the latest version. -We also don't need to know how the web API works in order to use it. It may be written in a different programming language. It may talk to other web APIs we don't know about. All we need to know is how to talk to it. +We also don't need to know how the API works in order to use it. It may be written in a different programming language. It may talk to other APIs we don't know about. All we need to know is how to talk to it. This is called the **interface**. _Using_ fetch is simple. But we want to understand what is happening more completely. So let's take ourselves on a journey through time. @@ -52,10 +53,10 @@ graph TD Response ---> |sequence with| then{{βœ”οΈ then}} - WebAPIs((🧰 Web APIs)) --> |live in your browser| ClientAPIs{πŸ’» Client side APIs} + APIs((🧰 APIs)) --> |live in your browser| ClientAPIs{πŸ’» Client side APIs} ClientAPIs --> |like| setTimeout[(⏲️ setTimeout)] ClientAPIs --> |like| eventListener[(🦻🏾 eventListener)] - WebAPIs --> |live on the internet| ServerAPIs{🌐 Server side APIs} + APIs --> |live on the internet| ServerAPIs{🌐 Server side APIs} ServerAPIs --> |serve our| Data[(πŸ’Ύ Data)] Data --> |as a| Response diff --git a/content/js3/blocks/internet/index.md b/content/en/js3/blocks/internet/index.md similarity index 100% rename from content/js3/blocks/internet/index.md rename to content/en/js3/blocks/internet/index.md diff --git a/content/js3/blocks/latency/index.md b/content/en/js3/blocks/latency/index.md similarity index 72% rename from content/js3/blocks/latency/index.md rename to content/en/js3/blocks/latency/index.md index 798161292..a016bd8a9 100644 --- a/content/js3/blocks/latency/index.md +++ b/content/en/js3/blocks/latency/index.md @@ -14,12 +14,12 @@ graph LR Request --> |has a latency| TimeProblem[πŸ—“οΈ Time Problem] ``` -Instead of already having our data, we are now sending a request over the network to another computer, and then waiting for that computer to send us a response back. - -Now that our data is going on a journey over a network, we introduce the problem of latency. +Instead of already having our data, we are now sending a request over the network to another computer, and then waiting for that computer to send us a response back. Now that our data is going on a journey over a network, we introduce the problem of **latency**. Latency is the time taken for a request to traverse the network. > πŸ’‘ Network latency is travel time. -Why is latency a problem? Because it means we need to **wait** for our data. But our program can only do one thing at a time - if we stopped our program to wait for data, then we wouldn't be able to do anything else. We need to handle this time problem. Programming often involves time problems, and latency is just one of them. +Why is latency a problem? Because it means we need to **wait** for our data. But our program can only do one thing at a time - if we stopped our program to wait for data, then we wouldn't be able to do anything else. We need to handle this time problem. + +Programming often involves time problems, and latency is just one of them. diff --git a/content/js3/blocks/using-fetch/index.md b/content/en/js3/blocks/using-fetch/index.md similarity index 74% rename from content/js3/blocks/using-fetch/index.md rename to content/en/js3/blocks/using-fetch/index.md index b8504b492..45983e043 100644 --- a/content/js3/blocks/using-fetch/index.md +++ b/content/en/js3/blocks/using-fetch/index.md @@ -10,15 +10,14 @@ emoji= '🧩' 3="Fetch data from a server side API" +++ -So now we have these pieces of our giant concept map +So now we have these four pieces of our giant concept map -πŸ—“οΈ we know that sending πŸ“€ requests over a network takes time -🧡 we know that we should not stop our program to wait for data -πŸ“€ we know that we can send a request using `fetch()` -πŸ• we know that `fetch` is a πŸ’» client side 🧰 Web API -πŸ«±πŸΏβ€πŸ«²πŸ½ we know that `fetch` returns a `Promise`? (...this last one is pending) +1. πŸ—“οΈ we know that sending πŸ“€ requests over a network takes time +2. 🧡 we know that we should not stop our program to wait for data +3. πŸ“€ we know that we can send a request using `fetch()` +4. πŸ• we know that `fetch` is a πŸ’» client side 🧰 Web API -But we still don't know how to use `fetch` to get data from a server side API. Let's find out. Run this code in the console in your browser. +We _don't_ yet know that `fetch` returns a `Promise` and we will explore this next time. And we still don't know how to use `fetch` to get data from a server side API. Let's find this out now. Run this code in the console in your browser. ```js const endpoint = "//curriculum.codeyourfuture.io/dummy-apis/films.json"; diff --git a/content/js3/blocks/promises/index.md b/content/js3/blocks/promises/index.md deleted file mode 100644 index 56bfa7cbf..000000000 --- a/content/js3/blocks/promises/index.md +++ /dev/null @@ -1,9 +0,0 @@ -+++ -title = 'What is a Promise?' -headless = true -time = 30 -facilitation = false -emoji= '🧩' -[objectives] - 1='' -+++ diff --git a/content/js3/blocks/then/index.md b/content/js3/blocks/then/index.md deleted file mode 100644 index 0e3ae14e7..000000000 --- a/content/js3/blocks/then/index.md +++ /dev/null @@ -1,9 +0,0 @@ -+++ -title = 'Making sense of .then()' -headless = true -time = 30 -facilitation = false -emoji= '🧩' -[objectives] - 1='' -+++ From 9209cc20983244647cb061a8ccc4e3005b879bc3 Mon Sep 17 00:00:00 2001 From: Sally McGrath Date: Fri, 22 Dec 2023 15:21:09 +0000 Subject: [PATCH 08/12] TEMP fix for mermaid it should be a web component --- content/en/js3/blocks/fetching-data/index.md | 2 +- .../render-codeblock-mermaid.html.html | 27 ++++++++++++++++++- layouts/partials/scripts.html | 3 --- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/content/en/js3/blocks/fetching-data/index.md b/content/en/js3/blocks/fetching-data/index.md index 61add2a58..9d51c3f0a 100644 --- a/content/en/js3/blocks/fetching-data/index.md +++ b/content/en/js3/blocks/fetching-data/index.md @@ -26,7 +26,7 @@ We also don't need to know how the API works in order to use it. It may be writt _Using_ fetch is simple. But we want to understand what is happening more completely. So let's take ourselves on a journey through time.
-πŸ‘‰πŸΎ Unfurl to see the journey (we will explain this all below!) +πŸ‘‰πŸΎ Unfurl to see the journey (we will explain this in little pieces) ```mermaid graph TD diff --git a/layouts/_default/_markup/render-codeblock-mermaid.html.html b/layouts/_default/_markup/render-codeblock-mermaid.html.html index 80530c564..108d9d2ee 100644 --- a/layouts/_default/_markup/render-codeblock-mermaid.html.html +++ b/layouts/_default/_markup/render-codeblock-mermaid.html.html @@ -1,4 +1,3 @@ -{{- .Page.Store.Set "hasMermaid" true -}}
{{- .Inner | safeHTML }}
+ diff --git a/layouts/partials/scripts.html b/layouts/partials/scripts.html index 157461295..c6f997228 100644 --- a/layouts/partials/scripts.html +++ b/layouts/partials/scripts.html @@ -8,6 +8,3 @@ {{ $tabs := resources.Get "scripts/tab-panels.js" | resources.Minify }} - From 1f2c2abf8dfae6e0b08de9dcd93fe7b4d8bf9039 Mon Sep 17 00:00:00 2001 From: Sally McGrath Date: Fri, 22 Dec 2023 15:59:00 +0000 Subject: [PATCH 09/12] rm promise log example skip straight to film fetch --- content/en/js3/blocks/asynchrony/index.md | 2 ++ content/en/js3/blocks/fetching-data/index.md | 2 ++ content/en/js3/blocks/using-fetch/index.md | 31 +++++++------------- 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/content/en/js3/blocks/asynchrony/index.md b/content/en/js3/blocks/asynchrony/index.md index 14534269e..e5692d849 100644 --- a/content/en/js3/blocks/asynchrony/index.md +++ b/content/en/js3/blocks/asynchrony/index.md @@ -61,6 +61,8 @@ We use a function as a way of wrapping up the code that needs to be run later on {{}} {{}} +### 🧠 Recap our concept map + ```mermaid graph LR TimeProblem[πŸ—“οΈ Time Problem] --> |caused by| SingleThread[🧡 Single thread] diff --git a/content/en/js3/blocks/fetching-data/index.md b/content/en/js3/blocks/fetching-data/index.md index 9d51c3f0a..70a620a59 100644 --- a/content/en/js3/blocks/fetching-data/index.md +++ b/content/en/js3/blocks/fetching-data/index.md @@ -15,6 +15,8 @@ So far we have displayed film data stored in our JavaScript code. But real appli > _When_ the page first loads > _Then_ the page should `fetch` and display the list of film data, including the film title, times and film certificate +### πŸ’» Client side and 🌐 Server side APIs + We will use [`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch), a {{}} A client side [Web API](https://developer.mozilla.org/en-US/docs/Web/API) lives in the browser. They provide programmatic access _to_ built-in browser functions _from_ JavaScript. {{}}. Fetch will fetch our data from the {{}} A server side API lives on a server. They provide programmatic access _to_ data or functions stored on the server _from_ JavaScript. {{}}. diff --git a/content/en/js3/blocks/using-fetch/index.md b/content/en/js3/blocks/using-fetch/index.md index 45983e043..eb0f3213e 100644 --- a/content/en/js3/blocks/using-fetch/index.md +++ b/content/en/js3/blocks/using-fetch/index.md @@ -5,31 +5,20 @@ time = 20 facilitation = false emoji= '🧩' [objectives] -1="List 4 preceding concepts of asynchronous programming in JavaScript" -2="Identify unknown concepts still to be learned" -3="Fetch data from a server side API" +1="List 5 preceding concepts of asynchronous programming in JavaScript" +2="Identify 2 unknown concepts still to be learned" +3="Fetch data from a server side API using a client side Web API" +++ -So now we have these four pieces of our giant concept map +So now we have these pieces of our giant concept map -1. πŸ—“οΈ we know that sending πŸ“€ requests over a network takes time -2. 🧡 we know that we should not stop our program to wait for data -3. πŸ“€ we know that we can send a request using `fetch()` -4. πŸ• we know that `fetch` is a πŸ’» client side 🧰 Web API +1. πŸ“€ we know that we can [send a request](#fetching-data) using `fetch()` +1. πŸ• we know that `fetch` is a [πŸ’» client side 🧰 Web API](#fetching-data) +1. πŸ—“οΈ we know that sending πŸ“€ requests over a network takes [time](#latency) +1. 🧡 we know that we should [not stop our program](#asynchrony) to wait for data +1. πŸͺƒ we know that we can [use callbacks](#callbacks) to manage events -We _don't_ yet know that `fetch` returns a `Promise` and we will explore this next time. And we still don't know how to use `fetch` to get data from a server side API. Let's find this out now. Run this code in the console in your browser. - -```js -const endpoint = "//curriculum.codeyourfuture.io/dummy-apis/films.json"; -const fetchPromise = fetch(endpoint); -const _ = fetchPromise.then((response) => { - console.log(response.json()); -}); -``` - -In the console, you can see a `Promise` was logged. A `Promise` is a placeholder which contains some data, but where the data may not be known yet. If you expand the `PromiseResult`, you should see some data which was returned from a server. - -So that's how we use `fetch` to get data from a server side API. In [our filterFilms code](https://curriculum.codeyourfuture.io/filterfilms), we can replace the films array with the data fetched from the server. +But we still don’t know how to use `fetch` to get data from a server side API. Let’s find this out now. In [our filterFilms code](https://curriculum.codeyourfuture.io/filterfilms), replace the films array with data fetched from a server. ```js // Begin with an empty state From 1579db14caedf7d4dc7c7174b20af4191d382a9c Mon Sep 17 00:00:00 2001 From: Sally McGrath Date: Fri, 22 Dec 2023 19:15:30 +0000 Subject: [PATCH 10/12] how did that get in there autocomplete strikes again --- layouts/_default/_markup/render-codeblock-mermaid.html.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layouts/_default/_markup/render-codeblock-mermaid.html.html b/layouts/_default/_markup/render-codeblock-mermaid.html.html index 108d9d2ee..a864748b3 100644 --- a/layouts/_default/_markup/render-codeblock-mermaid.html.html +++ b/layouts/_default/_markup/render-codeblock-mermaid.html.html @@ -10,7 +10,7 @@ From 5d0adb314a0ea4137824cddc58f3c942bcbea628 Mon Sep 17 00:00:00 2001 From: Sally McGrath Date: Wed, 27 Dec 2023 09:35:48 +0000 Subject: [PATCH 12/12] moving the script call too the ultimate fix for this will clearly be to write some kind of mutation observer in here --- layouts/_default/_markup/render-codeblock-mermaid.html.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/layouts/_default/_markup/render-codeblock-mermaid.html.html b/layouts/_default/_markup/render-codeblock-mermaid.html.html index 9e045268d..a8d575a00 100644 --- a/layouts/_default/_markup/render-codeblock-mermaid.html.html +++ b/layouts/_default/_markup/render-codeblock-mermaid.html.html @@ -7,3 +7,6 @@ }
{{- .Inner | safeHTML }}
+