diff --git a/common-content/en/module/js3/asynchrony/index.md b/common-content/en/module/js3/asynchrony/index.md deleted file mode 100644 index b57c9840b..000000000 --- a/common-content/en/module/js3/asynchrony/index.md +++ /dev/null @@ -1,84 +0,0 @@ -+++ -title = 'Asynchrony : outside time' - -time = 40 -emoji= '⏳' -[objectives] -1="Define asynchrony" -2="Explain why we need asynchrony" -3="Identify an asynchronous method we have already used" -[build] - render = 'never' - list = 'local' - publishResources = false - -+++ - -We can handle latency using {{}}Asynchronous execution is running code in a different order than it was written.{{}} To understand asynchrony we first need to be clear about {{}}Synchronous execution is running 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**. - -### Event Loop - -We have already used asynchronous execution. We have defined `eventListener`s that _listen_ for events to happen, _then_ execute a callback function. - -```js -const search = document.getElementById("search"); -search.addEventListener("input", handleInput); -``` - -When we called `addEventListener` it didn't immediately call `handleInput`. - -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 the JavaScript language! 🀯 This means you can't use them in a Node REPL. But they are implemented in web browsers. The core of JavaScript (e.g. strings and functions) 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"); -search.addEventListener("input", handleInput); -``` - -The callback `handleInput` does not run until the user types. With `fetch`, the callback function does not 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. - -**πŸ‘‰πŸ½ [Visualise the Event Loop](http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIGNvbnNvbGUubG9nKCdZb3UgY2xpY2tlZCB0aGUgYnV0dG9uIScpOyAgICAKfSk7Cgpjb25zb2xlLmxvZygiSGkhIik7Cgpjb25zb2xlLmxvZygiV2VsY29tZSB0byB0aGUgZXZlbnQgbG9vcCIpOw%3D%3D!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D)** - -### 🧠 Recap our concept map - -```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/common-content/en/module/js3/capturing-events/index.md b/common-content/en/module/js3/capturing-events/index.md index 5fae89415..faa91f875 100644 --- a/common-content/en/module/js3/capturing-events/index.md +++ b/common-content/en/module/js3/capturing-events/index.md @@ -1,7 +1,6 @@ +++ title = 'Capturing the user event' - -time = 15 +time = 20 emoji= '🦻🏻' [objectives] 1='Add an event listener to a user input' @@ -9,7 +8,6 @@ emoji= '🦻🏻' render = 'never' list = 'local' publishResources = false - +++ We've introduced our state, and our render works for different values of that state. But users of our website can't change the `searchTerm` state themselves. We need to introduce a way for them to change the `searchTerm` state via the UI. @@ -26,33 +24,13 @@ function handleSearchInput(event) { } ``` -When the "input" event fires, our handler function will run. Inside the handler we can access the updated input value: `const searchTerm = event.target.value;` - -So our key steps are: - -1. Add an input event listener to the search box -2. In the handler, get `value` of input element -3. Set the new state based on this value. -4. Call our `render` function again. - -{{}} -But we're not going to do all of these at once! Stop and implement just the first two steps (adding the event listener, and getting the value), and `console.log` the search term. - -{{}} - -We will make sure this works before we try to change the UI. Why? If we try to add the event listener and something _doesn't_ work, we will only have a little bit of code to debug. - -If we tried to solve the whole problem (updating the UI) and something didn't work, we would have a _lot_ of code to debug, which is harder! - -We've now demonstrated that we can capture search text on every keystroke: +These listeners wait for specific events to occur, and when they do, they trigger a callback function we've defined. This gives us a way to make our code respond to user actions rather than running all at once. ```js -const searchBox = document.getElementById("search"); +const search = document.getElementById("search"); +search.addEventListener("input", handleInput); +``` -searchBox.addEventListener("input", handleSearchInput); +When we call `addEventListener`, it doesn't immediately execute the `handleInput` function. Instead, it sets up a listener that will run this function later. Event listeners are part of the web browser's Event API. But event listeners themselves aren't part of the core JavaScript language! When you create an event listener, you're making a request to a Web API to handle this functionality for you. In this pattern, the callback function (`handleInput`) only executes when a user types. These callback functions need to execute in response to user interactions. This lets us tell the browser exactly what actions to take once a particular event occurs. -function handleSearchInput(event) { - const searchTerm = event.target.value; - console.log(searchTerm); -} -``` +Callback functions are essential for handling user interactions in web browsers. They allow our code to execute in response to an event. The browser listens for events and executes our callback functions at the right time. It is our job to define what should happen when those events occur. diff --git a/common-content/en/module/js3/re-rendering/index.md b/common-content/en/module/js3/re-rendering/index.md index df2aa4812..732301e99 100644 --- a/common-content/en/module/js3/re-rendering/index.md +++ b/common-content/en/module/js3/re-rendering/index.md @@ -13,6 +13,37 @@ emoji= 'πŸ”' +++ +When the "input" event fires, our handler function will run. Inside the handler we can access the updated input value: `const searchTerm = event.target.value;` + +So our key steps are: + +1. Add an input event listener to the search box. +2. In the handler, get the `value` of input element. +3. Set the new state based on this value. +4. Call our `render` function again. + +{{}} +But we're not going to do all of these at once! Stop and implement just the first two steps (adding the event listener, and getting the value), and `console.log` the search term. + +{{}} + +We will make sure this works before we try to change the UI. Why? If we try to add the event listener and something _doesn't_ work, we will only have a little bit of code to debug. + +If we tried to solve the whole problem (updating the UI) and something didn't work, we would have a _lot_ of code to debug, which is harder! + +We've now demonstrated that we can capture search text on every keystroke: + +```js +const searchBox = document.getElementById("search"); + +searchBox.addEventListener("input", handleSearchInput); + +function handleSearchInput(event) { + const searchTerm = event.target.value; + console.log(searchTerm); +} +``` + Now that we've shown we can log the search text, we can set the new value of the `searchTerm` state, and re-render the page. We should have a page like this: diff --git a/common-content/en/module/js3/synchronous-execution/index.md b/common-content/en/module/js3/synchronous-execution/index.md new file mode 100644 index 000000000..af2e17526 --- /dev/null +++ b/common-content/en/module/js3/synchronous-execution/index.md @@ -0,0 +1,43 @@ ++++ +title = 'Synchronous execution' + +time = 10 +emoji= '⏳' +[objectives] +1="Define asynchrony" +2="Explain how synchronous execution works" +[build] + render = 'never' + list = 'local' + publishResources = false ++++ + +We can handle latency using {{}}Asynchronous execution is running code in a different order than it was written.{{}} To understand asynchrony we first need to be clear about {{}}Synchronous execution is running 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**. diff --git a/common-content/en/module/js3/using-fetch/index.md b/common-content/en/module/js3/using-fetch/index.md index b362a8f7a..3e6c3bb54 100644 --- a/common-content/en/module/js3/using-fetch/index.md +++ b/common-content/en/module/js3/using-fetch/index.md @@ -9,20 +9,43 @@ emoji= '🌐' render = 'never' list = 'local' publishResources = false - +++ -So now we have these pieces of our giant concept map +So now we have these pieces of our giant concept map: + +1. πŸ“€ We know that we can send a request using `fetch()` +2. πŸ• We know that `fetch` is a πŸ’» client-side 🧰 Web API that requires an HTTP connection +3. πŸ—“οΈ We know that sending requests over a network takes time +4. 🧡 We know that we should not stop our program to wait for data +5. πŸͺƒ We know that we can use Promises to manage asynchronous operations + +But we still don’t know how to use `fetch` to get data from a server side API. -1. πŸ“€ we know that we can send a request using `fetch()` -1. πŸ• we know that `fetch` is a πŸ’» client side 🧰 Web API -1. πŸ—“οΈ we know that sending requests over a network takes time -1. 🧡 we know that we should not stop our program to wait for data -1. πŸͺƒ we know that we can use callbacks to manage events +### Loading html files -But we still don’t know how to use `fetch` to get data from a server side API. Let’s find this out now. +When you double-click an HTML file in your file explorer to open it directly in your browser, you're using what's called the "file protocol" or "file scheme." In your browser's URL bar, you'll see something like: -Let's pick our film display exercise back up. Before we had a list of films hard-coded in our `state`. We're going to replace the films array with data fetched from a server. +``` +file:///Users/username/projects/my-website/index.html +``` + +The `file://` prefix indicates that your browser is reading the file directly from your computer's filesystem, without going through a web server. While this approach might seem convenient for simple HTML files, it will prevent us from using `fetch`. + +### Web Server Access: The HTTP Protocol + +Another approach involves using a local development server. You can create one using tools like [Python's built-in server](https://realpython.com/python-http-server/) or [npm's http-server](https://www.npmjs.com/package/http-server). These tools create a web server on your computer that serves your files using the HTTP protocol. Your browser will then access the files through a URL like: + +``` +http://localhost:8000/index.html +``` + +The `http://` prefix shows that you're accessing the file through a proper web server, even though that server is running on your own computer. + +You need to be using `http://` (or `https://`) _not_ `file://` in order to use `fetch`. + +## Using `fetch` + +Previously, we had a list of films hard-coded in our `state`. Now, let's continue using our concept map to fetch data from a server. ```js // Begin with an empty state @@ -36,15 +59,18 @@ const endpoint = "https://programming.codeyourfuture.io/dummy-apis/films.json"; const fetchFilms = async () => { const response = await fetch(endpoint); return await response.json(); -}; // Our async function returns a Promise +}; fetchFilms().then((films) => { - // When the fetchFilms Promise resolves, this callback will be called. state.films = films; render(); }); ``` -`fetch` returns a `Promise`; the `Promise` fulfils itself with a response; the response contains our data. +{{}} +Remember: If you see an error message about fetch not being allowed from `file://` URLs, that's your signal to serve your files through a local development server instead of opening them directly in the browser. +{{}} + +fetch returns a Promise; the Promise fulfils itself with a response; the response contains our data. -Next we will dig into `Promise`s, `async`, `await`, and `then`, and complete our concept map. +Next, we'll dig into `Promise`s, `async`, `await`, and `then` in more detail to complete our concept map. diff --git a/org-cyf-itp/content/data-flows/sprints/3/prep/index.md b/org-cyf-itp/content/data-flows/sprints/3/prep/index.md index 56a6999d8..0baf1f872 100644 --- a/org-cyf-itp/content/data-flows/sprints/3/prep/index.md +++ b/org-cyf-itp/content/data-flows/sprints/3/prep/index.md @@ -14,8 +14,8 @@ src="https://www.youtube.com/watch?v=J-0XkB54yp8" name="Latency" src="module/js3/latency" [[blocks]] -name="Asynchrony" -src="module/js3/asynchrony" +name="Synchronous execution" +src="module/js3/synchronous-execution" [[blocks]] name="Callbacks" src="module/js3/callbacks"