Commit 0509f44f authored by Nathan Bean's avatar Nathan Bean
Browse files

Added node intro chapter

parent 03db3f55
......@@ -25,7 +25,7 @@ It's basically an infinite loop that responds to messages, one message at a time
Here we see not just the event loop, but also the _event queue_. This is a queue that holds events until the event loop is ready to process them. It works like the first-in-first-out queues you built in your data structures course (although it may also consider priorities of events).
On the far right are some commoon sources for JavaScript events - user input, the network, and timers. These are often managed by the operating system, and with modern multiple-processor computers can happen _concurrently_, i.e. _at the same time_. This is one reason the queue is so important - it allows JavaScript to process the events _one at a time_.
On the far right are some comoon sources for JavaScript events - user input, the network, and timers. These are often managed by the operating system, and with modern multiple-processor computers can happen _concurrently_, i.e. _at the same time_. This is one reason the queue is so important - it allows JavaScript to process the events _one at a time_.
When the JavaScript VM has finished executing its current work, it pulls the next event from the event queue. This event is processed by the corresponding _event listener_ function that either 1) you wrote, or 2) is the default action. If neither exists, the event is discarded.
......@@ -64,7 +64,7 @@ There are many kinds of events in JavaScript; you can find a complete list in th
* [focus](https://developer.mozilla.org/en-US/docs/Web/Events/focus) triggered when an input gains focus (is the currently selected input)
* [blur](https://developer.mozilla.org/en-US/docs/Web/Events/blur) triggered when an input looses focus
* [blur](https://developer.mozilla.org/en-US/docs/Web/Events/blur) triggered when an input loses focus
* [click](https://developer.mozilla.org/en-US/docs/Web/Events/click) The primary mouse button was clicked. On old browsers this might trigger for any button
......@@ -72,7 +72,7 @@ There are many kinds of events in JavaScript; you can find a complete list in th
* [mousedown](https://developer.mozilla.org/en-US/docs/Web/Events/mousedown) A mouse button was pressed
* [mouseup](https://developer.mozilla.org/en-US/docs/Web/Events/mouseup) A mosue button was released
* [mouseup](https://developer.mozilla.org/en-US/docs/Web/Events/mouseup) A mouse button was released
## Timers
......
......@@ -7,7 +7,7 @@ date: 2018-08-24T10:53:26-05:00
Before we get too deep in the details of what a request is, and how it works, let's explore the primary kind of request you're already used to making - requests originating from a browser. Every time you use a browser to browse the Internet, you are creating a series of HTTP (or HTTPS) requests that travel across the networks between you and a web server, which responds to your requests.
To help illustrate how these requests are made, we'll once again turn to our developer tools. Open the example page <a href='{{<static "examples/1.3.1/index.html">}}' target='_blank'>this link</a>. On that tab, open your developer tools with `CTRL + SHIFT + i` or by right-clicking the page and selecting "Inspect" from the context menu. Then choose the "Network" tab:
To help illustrate how these requests are made, we'll once again turn to our developer tools. Open the example page <a href='{{<static "examples/1.2.1/index.html">}}' target='_blank'>this link</a>. On that tab, open your developer tools with `CTRL + SHIFT + i` or by right-clicking the page and selecting "Inspect" from the context menu. Then choose the "Network" tab:
![Selecting the network tab in the developer tools]({{<static "images/2.2.1.png">}})
......
......@@ -25,7 +25,7 @@ The _HTTP-Version_ indicates the version of the HTTP protocol that is being used
_SP_ refers to a space character.
The _Status-Code_ is a three-digit numeric representation of the response status. Common codes include 200 (OK), 403 (Not Found), and 500 (Server Error).
The _Status-Code_ is a three-digit numeric representation of the response status. Common codes include 200 (OK), 404 (Not Found), and 500 (Server Error).
The _Reason-Phrase_ is a plain-text explanation of the status code.
......
......@@ -5,3 +5,4 @@ weight: 10
date: 2018-08-24T10:53:26-05:00
---
JavaScript makes extensive use of asynchronous processing to tackle the challenge of concurrency. This includes the events we've already talked about (user events, network events and timers), but it has also been expanded to provide even more powerful features. The XMLHTTPrequest object allows JavaScript to request additional resources directly in an asynchronous manner, and the more recent Fetch API updates that approach. Web workers allow parallel JavaScript processes to be run in the browser. And new ES6 syntax and constructs like Promises and the async/await keywords make asynchronous functions easier to reason about and use. In this chapter, we will explore each of these topics.
\ No newline at end of file
---
title: "Concurrency Approaches"
pre: "2. "
weight: 20
date: 2018-08-24T10:53:26-05:00
---
Concurrency means "doing more than one thing at the same time." In computer science, concurrency can refer to ([1](https://en.wikipedia.org/wiki/Concurrency_(computer_science))) structuring a program or algorithm so that it can be executed out-of-order or in partial order, or ([2](https://en.wikipedia.org/wiki/Concurrent_computing)) actually executing computations in parallel. In modern-day programming, we're often talking about _both_. But to help us develop a stronger understanding, let's look at the two ideas one-at-a-time, and then bring it together.
## Concurrency
One of the earliest concurrency problems computer science dealt with was the efficient use of early computers. Consider a mainframe computer like the [PDP-1](https://en.wikipedia.org/wiki/PDP-1), once a staple of the university computer science department. In 1963, the base price of a PDP-1 was $120,000. Adjusted for inflation, this would be a price of a bit more than _one million dollars_ in 2020! That's a pretty big investment! Any institution, be it a university, a corporation, or a government agency that spent that kind of money would want to use their new computer as efficiently as possible.
Consider when you are working on a math assignment and using a calculator. You probably read your problem carefully, write out an equation on paper, and then type a few calculations into your calculator, and copy the results to your paper. You might write a few lines as you progress through solving the problem, then punch a new calculation into your calculator. Between computations, your calculator is sitting idle - not doing anything. Mainframe computers worked much the same way - you loaded a program, it ran, and spat out results. Until you loaded a new program, the mainframe would be idle.
### Batch Processing
An early solution was the use of [batch processing](https://en.wikipedia.org/wiki/Batch_processing), where programs were prepared ahead of time on punch-card machines or the like, and turned over to an IT department team that would then feed these programs into the computer. In this way, the IT staff could keep the computer working as long as there was batched work to do. While this approach kept the computer busy, it was not ideal for the programmers. Consier the calculator example - it would be as if you had to write out your calculations and give them to another person to enter into the calculator. And they might not get you your results for days!
Can you imagine trying to write a program that way? In the early days that was _exactly_ how CS students wrote programs - they would write an entire program on punch cards, turn it in to the computer staff to be batched, and get the results once it had been run. If they made a mistake, it would require another full round of typing cards, turning them in, and waiting for results!
Batch processing is still used for some kinds of systems - such as the generation of your DARS report at K-State, for sending email campaigns, and for running jobs on Beocat and other supercomputers. However, in mainframe operations it quickly was displaced by _time sharing_.
### Time Sharing
[Time-sharing](https://en.wikipedia.org/wiki/Time-sharing) is an appoach that has much in common with its real-estate equivalent that shares its name. In real estate, a time-share is a vacation property that is owned by multiple people, who take turns using it. In a mainframe computer system, a time sharing approach likewise means that multiple people share a single computer. In this approach, terminals (a monitor and keyboard) are hooked up to the mainframe. But there is one important difference between time-sharing real estate and computers, which is why we can call this approach _concurrent_.
Let's return to the example of the calcuator. In the moments between your typing an expression and reading the results, another student could type in thier expression, and get thier results. A time-sharing mainframe does exactly that - it take a few fractions of a second to advance each users' program, switching between different users at lightning speed. Consider a newspaper where twenty people might we writing stories at a given moment - each terminal would capture key presses, and send them to the mainframe when it gave its attention, which would update the text editor, and send the resulting screen data back to the terminal. To the individual users, it would appear the computer was only working with them. But in actuallity it was updating all twenty text editor program instances in real-time (at least to human perception).
Like batch processing, time-sharing is still used in computing today. If you've used the thin clients in the DUE 1114 lab, these are the current-day equivalents of those early terminals. They're basically a video card, monitor, and input device that are hooked up to a server that runs multiple VMs (virtual machines), one for each client, and switches between them constantly updating each.
### Multitasking
The [microcomputer revolution](https://en.wikipedia.org/wiki/Microcomputer) did not do away with concept. Rather, modern operating systems still use the basic concept of the approach, though in the context of a single computer it is known as [multitasking](https://en.wikipedia.org/wiki/Computer_multitasking). When you write a paper now, your operating system is switching between processes in much the same way that time-sharing switched between users. It will switch to your text editor, processing your last keystroke and updating the text on screen. Then it will shift to your music player and stream the next few thousand bytes of the song you're listening to the sound card. Then it will switch to your email program which checks the email server and it will start to notify you that a new email has come in. Then it will switch back to your text editor.
The thin clients in DUE 1114 (as well as the remote desktops) are therefore both time-sharing between VMs and multitasking within VMs.
## Parallel Processing
The second approach to concurrency invovles using _multiple_ computers in parallel. K-State's [Beocat](https://support.beocat.ksu.edu/BeocatDocs/index.php?title=Main_Page) is a good example of this - a supercomputer built of a lot of individual computer. But your laptop or desktop likely is as well; if you have a multi-core CPU, you actually have multiple processors built into your CPU, and each can run separate computational processes. This, it is entirely possible that as you are writing your term paper the text editor is running on one processor, your email application is using a second one, and your music is running on a third.
In fact, modern operating systems use both multitasking and parallel processing in tandem, spreading out the work to do across however many cores are available, and swapping between active processes to on those cores. Some programs also organize thier own computation to run on multiple processors - your text editor might actually be handling your input on one core, running a spellcheck on a second, and a grammar check on a third.
Remember our earlier discussion about scaling web servers? This is _also_ a parallel processing approach. Incoming HTTP requests are directed by a load balancer to a less-busy server, and that server formulates the response.
![Horizontal Scaling]({{<static "images/3.2.1.png">}})
### Multithreading
Individual programs can _also_ be written to execute on multiple cores. We typically call this approach [Multithreading](https://en.wikipedia.org/wiki/Thread_(computing)#Multithreading), and the individually executing portions of the program code _threads_.
These aren't the only ways to approach concurrency, but they are ones we commonly see in practice. Before we turn our attention to how asynchronous processes fit in though, we'll want to discuss some of the challenges that concurrency brings.
\ No newline at end of file
---
title: "Concurrency Challenges"
pre: "3. "
weight: 30
date: 2018-08-24T10:53:26-05:00
---
Implementing concurrency in computing systems comes with some specific challenges. Consider the multitasking approach where we have your text editor and your music player running at the same time. As the text editor process yields to the music player, the data and program elements it had loaded up into working memory, needs to be cleared out and replaced with the music player's data and program. However, the music player's data and program need to be retained _somewhere_ so that they can be swapped back in when the music player yields.
Modern operating systems handle this challenge by dividing working memory amongst all programs running (which is why the more programs you run, the more RAM you consume). Each running process is assigned a block of memory and _only_ allowed to use that memory. Moreover, data copied into the CPU (the L2 cache, L1 cache, and registers) may also be cached in memory for later restoration. You'll learn more about the details of this process if you take an Operating Systems course. But it is _very_ important that each running program is _only_ allowed to make changes in its own assigned memory space. If it wasn't, it could overwrite the data of another task!
{{% notice info %}}
In fact, an OS allowing a running program to overwrite another program's assigned memory is a _security vulnerability_, as this can involve overwriting part of the other _program_, changing how it actually works! Viruses, trojans, and worms are often written to exploit this kind of vulnerability.
{{% /notice %}}
While operating sytems normally manage the challenges of concurrency between running programs, when the program _itself_ is written to be concurrent, the program itself must be built to avoid accidentally overwriting its own memory in unexpected ways. Consider a text editor - it might have its main thread handling user input, and a second thread handling spell checking. Now the user has typed "A quick brow", and the spell checker is finding that "brow" is misspelled. It might try to underline the line in red, but in the intervening time, the user has deleted "brow", so the underlining is no longer valid!
Or consider image data. Applying a filter to an image is a computationally costly operation - typically requiring visiting each pixel in the image, and for some filters, visiting each pixel _around_ each pixel as part of the transformation. This would be a good use-case for multi-threading. But now imagine _two_ filters working in parallel. One might be applying a blur, and the other a grayscale transformation. If they were overwriting the old image data with their new filtered version, and were working at the same time, they might both start from the original pixels in the upper-right-hand corner. The blur would take longer, as it needs to visit neighboring pixels. So the grayscale filter writes out the first hundred pixels, and then the blur writes out its first hundred, over-writing the grayed pixels with blurred color pixels. Eventntually, the grayscale filter will get so far ahead of the blur filter that the blur filter will be reading in now-greyed out pixels, and blurring them. The result could well be a mismash of blurred color and gray-and-white splotches.
There are many different approaches that can be used to manage this challenge. One is the use of locks - locking a section of memory so only one thread can access it while it makes changes. In the filter example, the grayscale filter could lock the image data, forcing the blur filter to wait until it finishes. Locks work well, but must be carefully designed to avoid race conditions - where two threads cannot move forward because the other thread has already locked a resource the blocked thread needs to finish its work.
Asynchronous processing is another potential solution, which we'll look at next.
\ No newline at end of file
---
title: "Asynchronous Programming"
pre: "4. "
weight: 40
date: 2018-08-24T10:53:26-05:00
---
In asynchronous programming, memory collisons are avoided by not sharing memory between threads. A unit of work that can be done in parallel is split off and handed to another thread, and any data it needs is copied into that threads' memory space. When the work is complete, the second thread notifies the primary thread if the work was completed succesfully or not, and provides the resulting data or error.
In JavaScript, this notification is pushed into the event queue, and the main thread processes it when the event loop pulls the result off the event queue. Thus, the only memory that is shared between the code you've written in the Event Loop and the code running in the asynchronous process is the memory invovled in the event queue. Keeping this memory thread-safe is managed by the JavaScript interpreter. Thus, the code you write (which runs in the Event Loop) is essentially single-threaded, even if your JavaScript application is using some form of parallel processing!
Let's reconsider a topic we've already discussed with this new understanding - timers. When we invoke `setTimer()`, we are creating a timer that is managed asynchronously. When the timer elapses, it creates a timer 'event' and adds it to the event queue. We can see this in the diagram below.
![The timer and event loop]({{<static "images/3.4.1.png">}})
However, the timer is not actually an _event_, in the same sense that a `'click'` or `'keydown'` event is... in that those events are provided to the browser from the operating system, and the browser passes them along into the JavaScript interpreter, possibly with some transformation. In contrast, the timer is created from within the JavaScript code, though its triggering is managed asycnhronously.
In fact, both timers and events reprsent this style of asynchronous processing - both are managed by creating _messages_ that are placed on the event queue to be processed by the interpreter. But the timer provides an important example of how asynchronous programming works. Consider this code that creates a timer that triggers after 0 milliseconds:
```js
setTimeout(()=>{
console.log("Timer expired!");
}, 0);
console.log("I just set a timer.");
```
What will be printed first? The "Timer expired!" message or the "I just set a timer." message? You can try running this code in the console.
The answer is that "I just set a timer" will _always_ be printed first, because the second message won't be printed until the event loop pulls the timer message off the queue, and the line printing "I just set a timer" is executed as part of this pass in the event loop. The `setTimeout()` and `setInterval()` functions are what we call _asynchronous_ functions, as they trigger an asynchronous process. Once that process is triggered, execution immediately continues within the event loop, while the triggered process runs in parallel. Asynchronous functions typically take a function as an argument, known as a _callback function_, which will be triggered when the message corresponding to the asynchronous process is pulled off the event queue.
{{% notice warning %}}
Any code appearing after a call to an asynchronous function will be executed immedately after the asynchonous function is invoked, regardless of how quickly the asynchronous process generates its message and adds it to the event queue.
{{% /notice %}}
As JavaScript was expanded to take on new functionality, this asynchronous mechanism was re-used. Next, we'll take a look at an example of this in the use of AJAX to make HTTP and HTTPS requests.
{{< console >}}
\ No newline at end of file
---
title: "AJAX"
pre: "5. "
weight: 50
date: 2018-08-24T10:53:26-05:00
---
Asynchronous JavaScript and XML (AJAX) is a term coined by Jesse James Garrett to describe a technique of using the [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) object to request resources directly from JavaScript. As the name implies, this was originally used to request XML content, but the technique can be used with any kind of data.
### The XMLHttpRequest
The `XMLHttpRequest` object is modeled after how the `window` object makes web requests. You can think of it as a state machine that can be in one of several possible states, defined by both a constant and an unsigned short value:
* **UNSENT** or **0** The client has been created, but no request has been made. Analogus to a just-opened browser before you type an address in the address bar.
* **OPENED** or **1** The request has been made, but the response has not been recieved. The browser analogue would be you have just pressed enter after typing the address.
* **HEADERS_RECIEVED** or **2** The first part of the response has been processed. We'll talk about headers in the next chapter.
* **LOADING** or **3** The content of the response is being downloaded. In the browser, this would be the stage where the HTML is being recieved and parsed into the DOM.
* **DONE** or **4** The resource is fully loaded. In the DOM, this would be equivalent to the `'load'` event.
![The XMLHttpRequest ready states]({{<static "images/3.8.1.png">}})
#### XMLHttpRequest Properties
The XMLHttpRequest object aslo has a number of properties that are helpful:
* `readyState` - the current state of the property
* `response` - the body of the response, an `ArrayBuffer`, `Blob`, `Document`, or `DOMString` based on the value of the `responseType`
* `responseType` - the mime type of response
* `status` - returns an unsigned short with the HTTP response status (or 0 if the response has not been recieved)
* `statuText` - returns a string containing the response string fro the server, i.e. `"200 OK"`
* `timeout` - the number of milliseconds the request can take before being terminated
#### XMLHttpRequest Events
The XMLHttpRequest object implements the `EventTarget` interface, just like the `Element` and `Node` of the DOM, so we can attach event listeners with `addEventListener()`. The specific events we can listen for are:
* `abort` - fired when the request has been aborted (you can abort a request with the [XMLHttpRequest.abort()](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/abort) method)
* `error` - fired when the request encountered an error
* `load` - fired when the request completes sucessfully
* `loadend` - fired wehn the request has completed, either because of success or after an abort or error.
* `loadstart` - fired wehn the request has started to load data
* `progress` - fired periodically as the request recieves data
* `timeout` - fired wehn the progress is expired due to taking too long
Several of these events have properties you can assign a function to directly to capture the event:
* `onerror` - corresponds to the `error` event
* `onload` - corresponds to the `load` event
* `onloadend` - corresponds to the `loadend` event
* `onloadstart` - corresponds to the `loadstart` event
* `onprogress` - corresponds to the `progress` event
* `ontimeout` - corresponds to the `timeout` event
In addition, there is an `onreadystatechange` property which acts like one of these properties and is fired every time the state of the request changes. In older code, you may see it used instead of the `load` event, i.e.:
```js
xhr.onreadystatechange(function(){
if(xhr.readyState === 4 && xhr.status === 200) {
// Request has finished successfully, do logic
}
});
```
### Using AJAX
Of course the point of learning about the XMLHttpRequest object is to perform AJAX requests. So let's turn our attention to that task.
#### Creating the XMLHttpRequest
The first step in using AJAX is creating the XMLHttpRequest object. To do so, we simply call its constructor, and assign it to a variable:
```js
var xhr = new XMLHttpRequest();
```
We can create as many of these requests as we want, so if we have multiple requests to make, we'll usually create a new XMLHttpRequest object for each.
#### Attaching the Event Listeners
Usually, we'll want to attach our event listener(s) before doing anything else with the `XMLHttpRequest` object. The reason is simple - because the request happens asynchronously, it is entirely possible the request will be finished _before_ we add the event listener to listen for the `load` event. In that case, our listener will _never_ trigger.
At a minimum, you probably want to listen to `load` events, i.e.:
```js
xhr.addEventListener('load', () => {
// do something with xhr object
});
```
But it is also a good idea to listen for the `error` event as well:
```js
xhr.addEventListener('error', () => {
// report the error
});
```
#### Opening the XMLHttpRequest
Much like when we manually made requests, we first need to open the connection to the server. We do this with the [XMLHttpRequest.open()](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/open) method:
```js
xhr.open('GET', 'https://imgs.xkcd.com/comics/blogofractal.png');
```
The first arguement is the [HTTP request method]({{<ref "/02-http/04-request-methods" >}}) to use, and the second is the [URL]({{<ref "/02-http/05-uris-and-urls">}}) to open.
There are also three optional parameters that can be used to follow - a boolean determining if the request should be made asynchronously (default `true`) and a user and password for HTTP authentication. Since AJAX requests are normally made asynchronously, and HTTP authentication has largely been displaced by more secure authentication approaches, these are rarely used.
#### Setting Headers
After the `XMLHttpRequest` has been opened, but before it is sent, you can use [XMLHttpRequest.setRequestHeader()](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader) to set any [request headers]({{<ref "/02-http/06-request-headers">}}) you need. For example, we might set an `Accept` header to `image/png` to indicate we would like image data as our response:
```js
xhr.setRequestHeader('Accept', 'image/png');
```
#### Sending the XMLHttpRequest
Finally, the [XMLHttpRequest.send()](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send) method will send the request asynchronously (unless the `async` parameter in `XMLHttpRequest.open()` was set to `false`). As the response is recieved (or fails) the appropriate event handlers will be triggered. To finish our example:
```js
xhr.send();
```
{{% notice info %}}
A second major benefit of the JQuery library (after simplifying DOM querying and manipulation) was its effort to simplify AJAX. It provides a robust wrapper around the `XMLHttpRequest` object with the [jQuery.ajax()](https://api.jquery.com/jquery.ajax/) method. Consider the AJAX request we defined in this chapter:
```js
var xhr = new XMLHttpRequest();
xhr.addEventListener('load', () => {
// do something with xhr object
});
xhr.addEventListener('error', () => {
// report the error
});
xhr.open('GET', 'https://imgs.xkcd.com/comics/blogofractal.png');
xhr.setRequestHeader('Accept', 'image/png');
xhr.send();
```
The equivalent jQuery code would be:
```js
jQuery.ajax("https://imgs.xkcd.com/comics/blogofractal.png", {
method: 'GET',
headers: {
Accept: 'image/png'
},
success: (data, status, xhr) => {
// do something with data
},
error: (xhr, status, error) => {
// report the error
}
});
```
Many developers found this all-in-one approach simpler than working directly with `XMLHttpRequest` objects. The W3C adopted some of these ideas into the Fetch API, which we'll take a look at shortly.
{{% /notice %}}
\ No newline at end of file
---
title: "AJAX"
pre: "8. "
weight: 80
date: 2018-08-24T10:53:26-05:00
---
Asynchronous JavaScript and XML (AJAX) is a term coined by Jesse James Garrett to describe a technique of using the [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) object to request resources directly from JavaScript. As the name implies, this was originally used to request XML content, but the technique can be used with any kind of data.
The `XMLHttpRequest` object is modeled after how the `window` object makes web requests. You can think of it as a state machine that can be in one of several possible states:
* **UNSENT** The client has been created, but no request has been made. Analogus to a just-opened browser before you type an address in the address bar.
* **OPENED** The request has been made, but the response has not been recieved. The browser analogue would be you have just pressed enter after typing the address.
* **HEADERS_RECIEVED** The first part of the response has been processed. We'll talk about headers in the next chapter.
* **LOADING** The content of the response is being downloaded. In the browser, this would be the stage where the HTML is being recieved and parsed into the DOM.
* **DONE** The resource is fully loaded. In the DOM, this would be equivalent to the `'load'` event.
We can build an AJAX request to retrieve any kind of file from the Internet. For example, to load the smile image we discussed in the last section, we could use:
```js
var xhr = new XMLHttpRequest();
xhr.addEventListener('load', function(event){
console.log(xhr.response);
});
xhr.open("GET", "smile.png");
xhr.send();
```
\ No newline at end of file
......@@ -6,7 +6,7 @@ date: 2018-08-24T10:53:26-05:00
---
Node is an open-source, cross-platform JavaScript runtime environment build on Google's V8 engine. It was created by Ryan Dahl in 2009 to allow for server-side scripting in JavaScript.
![Ryan Dahl](.guides/img/440px-Ryan_Dahl.jpg)
![Ryan Dahl]({{< static "images/Ryan_Dahl.jpg" >}})
## ECMAScript Support
......
---
title: "Event Loop"
pre: "2. "
weight: 20
date: 2018-08-24T10:53:26-05:00
---
Node adopts an asynchronous event-driven approach to computing, much like JavaScript does in the browser. For example, when we set up a HTTP server in Node, we define a function to call when a HTTP request (an event) is received. As requests come in, they are added to a queue which is processed in a FIFO (first-in, first-out) manner.
![JavaScript Event Loop]({{<static "images/4.2.1.png">}})
In addition to events, Node implements many asynchronous functions for potentially blocking operations. For example, consider file I/O. If you write a program that needs to read a file, but when it attempts to do so the file is already open in another program, your program must wait for it to become available. In the meantime, your program is _blocked_, and its execution pauses. A real-world analogue would be a checkout line at a store. If the cashier is ringing up a customer and finds an item without a price tag, they may leave their station to go find the item on the shelves. While they are away, the line is _blocked_, everyone in line must wait for the cashier to return.
There are two basic strategies to deal with potentially blocking operations - **multi-threading** and **asynchronous processing**. A multi-threading strategy involves parallelizing the task; in our store example, we'd have additional cash registers, cashiers, and lines. Even if one line is blocked, the others continue to ring up customers. In contrast, asynchronous processing moves the potentially blocking task into another process, and continues with the task at hand. When the asynchronous process finishes, it queues its results for the main process to resume. In our store example, this would be the cashier sending another employee to find the price, suspending the sale on the register, and continuing to check out other customers while the first customer waits. When the other employee returns with a price, the cashier finishes checking out the current customer, then resumes the first customer's transactions.
Node uses this asynchronous model to handle most potentially blocking operations (and often provides a synchronous approach as well). When possible, the asynchronous process is handled by the operating system, but the Node runtime also maintains a pool of threads to farm tasks out to.
The Node event loop is divided into a series of phases - each queues the associated kinds of events and processes them in a round-robin fashion. This helps ensure that one kind of event can't overwhelm the system:
![JavaScript ]({{<static "images/4.2.2.png">}})
For a more detailed breakdown of the Node event loop, check out [this blog post](https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and-its-metrics-c4907b19da4c) by Daniel Khan or the [Node Event Loop Documentation](https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/).
---
title: "Asynchronous Functions"
pre: "3. "
weight: 30
date: 2018-08-24T10:53:26-05:00
---
The benefit of the asynchronous approach is that all user-written code runs in a single-threaded environment while avoiding blocking. This means for the most part, we can write code the way we are used to, with a few tweaks for asynchronous functions.
Consider the two approaches for reading and printing the contents of a file, below:
```js
const fs = require('fs');
// Synchronous approach
var data = fs.readFileSync('file.txt');
console.log(data);
// Asynchronous approach
fs.readFile('file.txt', function(err, data){
console.log(data);
});
```
In the synchronous function, the contents of the file are _returned_, and assigned to the variable `data`. Conversely, in the asynchronous approach the file contents are passed into a _callback_ function that is invoked when the asynchronous process finishes (and when the callback phase of the Node event loop is reached). The function itself returns nothing (`undefined` in Node). The important difference between the two is in the first approach, the program waits for the file to be read. In the second, the program keeps executing lines of code after the asynchronous call, even though the file hasn't been read yet.
## Asynchronous Callback Structure
In most Node libraries, the callback function provided to the asynchronous function follows the same format - the first parameter is an error value, which will be populated with text or object if an error occurred, and otherwise will be a __falsey__ value (a value that evaluates to false, like `false`, `null`, `undefined`, or `0`). Successive arguments are the data the function was intended to retrieve - i.e. the contents of the file in the above example. Of course, if an error _was_ encountered, the later values may be wrong. Thus, most programmers follow the pattern of checking for an error at the start of the callback, and halting execution if one is encountered. Rewriting the example above, we would see:
```js
fs.readFile("file.txt", function(err, data){
if(err) return console.error(err);
console.log(data);
});
```
If `err` is a __truthy__ value (any non-falsey value, in this case an Exception object or a string), we log the error to the console and return, halting execution of the rest of the function.
## Common Asynchronous Misconceptions
It is very important to understand that the callback is _executed at a future point in time_, and execution continues to further lines of code. Consider this example:
---
title: "Node Modules"
pre: "6. "
weight: 60
title: "Modules"
pre: "4. "
weight: 40
date: 2018-08-24T10:53:26-05:00
---
One major feature Node introduced to JavaScript was the ability to encapsulate code into separate files using _modules_. The approach adopted by Node is the __CommonJS__ module pattern.
{{% notice warning %}}
Node's use of modules predates ECMA6's adoption of modules, and the CommonJS approach Node adopted is fundamentally different than the ECMA6 version. For Node 10 (installed on your Codio Box), ECMA6 modules are an experimental feature that has to be enabled with a flag when invoking the node command, i.e.:
```text
$ node --experimental-modules [file to run]
```
In later versions of Node (12-14) ECMA6 modules can be used without the flag by the module file the _.mjs_ extension. However, this approach is still considered experimental.
{{% /notice %}}
## Writing a Module
A module is simply a JavaScript file (typically saved with a _js_ extension). Code within the module is locally scoped to the module; code intended to be accessed outside of the module must be explicitly _exported_ by assigning it to the `module.exports` parameter. This example exports a function to print "Hello World":
......
---
title: "Packages"
pre: "5. "
weight: 50
date: 2018-08-24T10:53:26-05:00
---
The Node Package Manager allows you to create a _package_ representing your project. This is similar to Visual Studio's idea of a _project_ - a package is a complete Node program.
Just as Visual Studio adds solution and project files, a Node package adds a file named _package.json_ and a directory named *node_modules*.
## The Package File
Every node package has in its top-level directory a file named _package.json_. This JSON file provides important information about the project, including:
* The name of the project
* The version of the project
* The author of the project
* The entry point (the file that should be processed first, much like a C# _Program.cs_ file or C++ _main.cpp_ file). Owing to its roots as a language for developing webservers, the default is _index.js_, though it can be anything you want (many projects use _server.js_ or _main.js_).
* Any scripts associated with the project (often we'll have scripts to run and test the project)
* Any dependencies of the project (these are additional packages that are copied into the *node_modules* file)
* The home repository of the project (often a GitHub repository, though other options are possible)
* The license under which this package is released
Most of the properties of the _package.json_ are optional, and there are options I have listed above are not comprehensive. The _package.json_ object format is described in great detail in the [npm documentation](https://docs.npmjs.com/files/package.json).
## Semantic Versioning
Node packages use [semantic versioning](https://semver.org/), a numbering scheme that uses three numbers separated by periods in the pattern `MAJOR.MINOR.PATCH`. For example, your Codio Box is likely running **Ubuntu 18.04.3** - that is Ubuntu, major release 18, minor release 4, patch 3. If its developers found a bug or security vulnerablity and fixed it, they would release a new patch version, i.e. **Ubuntu 18.04.4**. If they made some improvements that don't change the way you work with the operating system, those might be a minor relase, i.e. **Ubuntu 18.05.0** (note that the patch release number starts over at 0). And if a major change in the way the software works was made, that would be a major release, i.e. **Ubuntu 19.0.0**. Additionally, you probably have seen the program listed as **Ubuntu 18.04.4 LTS**. The LTS is not part of semantic versoning, but indicates this is a _long term support_ release, i.e. one the developers have committed to fixing problems with for a specific duration of time.
When releasing your own Node packages, you should strive to practice using semantic versioning. That way you get into the habit, and it will be easier when you become a professional developer. Another good practice is to have a _changelog_ - a text or markdown file that lists the changes made in each succesive version of the program, usually as a bulleted list.
## Initializing the Package
You can manually create the _package.json_ file, but npm also provides a wizard to make this process easier. From the terminal, while at the root directory of your project, enter the command:
```bash
$ npm init
```
This will launch the wizard, asking you a series of questions used to create the project. It will also offer default options for many of the values; you can simply press the space bar to accept these. Moreover, if your directory contains an already-initailized git repository, it will use that repository's origin as the basis for the repository option. The wizard will create the _package.json_ file in the project's root directory.
Next we'll look at some aspects of the package in more detail.
\ No newline at end of file
---
title: "Dependencies"
pre: "6. "
weight: 60
date: 2018-08-24T10:53:26-05:00
---
A second great benefit of creating your project as a Node package is that dependences can be managed using the Node Package Manager (npm). You can install any Node package with the command `$npm install [package name]`. This command looks for the corresponding package in an online repository, and if it is found, downloads it and saves it to the subdirectory _node_modules_ in your package directory.
It also creates an entry in the _package.json_ file corresponding to the package you installed, and also an entry in the _package.lock.json_ file. The entry in your _package.json_ file may specify a specific version, i.e.:
```json
{
"name": "example-package",
"version": "1.0.0",
"dependencies": {
"foo": "2.1.3",
"bar": "^1.1.0",
"doh": "~4.3.2"
}
}
```
The `^` before the `"bar"` dependency indicates that npm can use any _minor release_ after this version, i.e. we could use **bar 1.2.1** but not bar **2.1.1**. The `~` before the `"doh"` dependency indicates that npm can use any _patch release_ after this version, i.e. **doh 4.3.4** but not **doh 4.4.0**. Because we specified the _exact_ version for `"foo"`, it will always install **foo 2.1.3**. We could also indicate we will accept _any_ major version with an `*`, but this is rarely used. Additionally, we can specify a git repo or a location on our hard drive, though these approaches are also not commonly used.
The reason we want the dependency information specified this way is that when we commit our package to source control, we typically _exclude_ the dependencies found in **node_modules**. As this folder can get quite large, this saves us significant space in our repository. When you clone your package to a new location, you can re-install the dependencies with the command:
```bash
$ npm install
```
This will pull the latest version of each dependency package allowable. Additionally, some modules may have thier own dependencies, in which case npm will strive to find a version that works for all requirements.
Finally, the _package.lock.json_ contains the _exact_ version of the dependencies installed. It _is_ intended to be committed to your repository, and if it exists it will make the `npm install` command install the exact same packages. This can help avoid problems where two versions of a package are slightly different.
## Development Dependency
In addition to regular dependencies, we can specify dependencies we only need during development. Adding the `--save-dev` flag to the command will add the package to a _development_ dependency list in your _package.json_ file. Development dependencies are only installed in the development environment; they are left out in a production environment.
|||info
## The NPM Registry
There are many ways to connect with dependencies, but one of the easiest and most popular is to use the [NPM Registry](https://www.npmjs.com/), a searchable, online directory of npm packages maintained by npm, Inc. You can search for keywords and (hopefully) fin a project that fits your needs.
|||
---
title: "Git"
pre: "7. "
weight: 70
date: 2018-08-24T10:53:26-05:00
---
Most Node packages are made available as [git](https://git-scm.com) repositories, and _npm_ has built-in support for using git.
## The Repository Property
In your _package.json_ file, you can specify a `"repository"` property, which specifies where the repository for this project exists. Consider the following example of the npm command-line interface package:
```json
"repository": {
"type" : "git",
"url" : "https://github.com/npm/cli.git"
}
```
For many open-source projects, the repository is located on Github, a GitHub gist, BitBucket, or a Gitlab instance. These can be specified with a shorthand, which matches the corresponding `npm install` argument:
```json
"repository": "npm/npm"
"repository": "github:user/repo"
"repository": "gist:11081aaa281"
"repository": "bitbucket:user/repo"
"repository": "gitlab:user/repo"
```
If your project folder already is set up as a git repo _before_ you run `$npm init`, then the wizard will suggest using the existing repository.
## The .gitignore File
Like any git repo, there are some files you will want to exclude from version control. The most important of these is the _node_modules_ folder, which we exclude for two reasons:
1. The folder's contents are large, and are available from the original sources specified in your package's dependencies - therefore they represent significant and unnecessary glut in a repository.
2. Some portions of your dependencies may be compiled from C code as they are installed. Since C code is compiled into binaries for a specific target machine's architecture, you will encounter errors if your development and production machines are different. Re-installing packages in the production machine with `$npm install` avoids this.
Therefore, you should include _at least_ this line in your _.gitignore_ file:
```text
node_modules/
```
It's also a good idea to leave out any logging files:
```text
logs
*.log
```
You may also want to look at Github's boilerplate [Node .gitigore template](https://github.com/github/gitignore/blob/master/Node.gitignore), which adds additional rules based on many popular Node frameworks (adding an ignore for a file or directory that doesn't exist in your project is harmless).