11
Creating applications

A graphical representation shows a adult man walking on the bridge, while the vehicles passes on the road below the bridge.

What you will learn

In this chapter, we are going to make some applications. We are going to discover how JavaScript programs can work with functions to control how data is processed and then move on to consider how JavaScript applications can fetch services from the Internet. Finally, we’ll use the Node.js platform to create a JavaScript-powered web server of our own and build an application that can consume services from it. At the end of this chapter, you will know how web applications really work and how to build one of your own.

Data analysis

Create extra Fashion Shop functions

Read the weather

Node.js

Install and test Node.js

Deploying a Node.js server

What you have learned

Data analysis

We are going to start off by performing some analysis for the Fashion Shop application that we created in Chapter 10. This will allow us to explore some advanced features of JavaScript functions and discover how easy it is to perform analysis of the contents of arrays of data. We are going start by considering how a JavaScript program can display a list of items.

Fashion Shop stock list

At the end of Chapter 10, we had created an application to manage the stock in a Fashion Shop. The shop contains a variety of different stock items, each of which is represented by an instance of a particular object. The entire stock is stored as an array of stock items. One of the features of the application lets the user see all the stock in the shop in one long list (Figure 11-1). Now we are going to explore how this works.

A screenshot shows the 'stock list' page of Imogen's fashion. It lists reference number, price, stock, description, color, pattern, and size in each reference number. The update button is displayed to the right of each reference number.

Figure 11-1 Fashion Shop stock list

The Fashion Shop application produces a stock list, as shown in Figure 11-1. Each stock item is displayed on a line of text. The item details on each line of the list are preceded by an Update button that can be pressed to update the stock details for that item. Let’s look at how the stock list is produced. When the user presses the button to produce the stock list, the following JavaScript function runs:

function doListFashionShop() {
    createListPage("Stock List", dataStore);
}

The function doListFashionShop calls the function createListPage. The createListPage function is provided with two arguments. The first argument is the heading for the list. In this case, the heading is “Stock List.” The second argument is the list of items to be displayed. In this case, the program is listing the entire contents of the data store. The function createListPage creates the list page and displays it. Let’s have a look at how that works.

A screenshot provides the JavaScript code to list the entire contents of the data store.

The function createList works through all the list items and calls the function createListElement for each one. The list element that createListElement returns is then added to the mainPage. The mainPage variable is the HTML element in the document that the browser is displaying. It is how the Fashion Shop application displays data to the user. The final thing we need to look at is the createListElement function, so let’s see how that works.

The screenshot shows the program with CreateListElement function.

The output from this function is an element that is used to display the item in the HTML document for the Fashion Shop application.

<p><button class="itemButton" onclick="doUpdateItem('4')">Update</button>
<p class="itemList">Ref:4 Price:10 Stock:14 Description:red plain dress
                    Color:red Pattern:plain<ic:ccc> Size:14</p></p>

This is the HTML produced by createListElement for one of the stock items. The HTML includes a button that will call the doUpdateItem function when the button is clicked. The call of the doUpdateItem function is given an argument, which is the stockRef of the item being displayed. In the above HTML, the element with stockRef 4 is being displayed. The doUpdateItem function finds the requested element and displays it for update.

Fashion Shop data analysis

Imogen has found the Fashion Shop application very useful. She especially likes the stock list feature. Now she would like to add some more data analysis features:

  • A list of items in sorted in order of the number in stock so that she can quickly discover which items are running low

  • A list of items sorted in descending order of price so that she can identify expensive items that might be worth discounting

  • A list of items sorted in order of “investment” (price times number of stock items) so that she can identify where she has spent the most money

  • A list of just the items that have zero stock

  • The total value of all her stock

You decide to implement this by adding a Data Analysis option to the main menu for the program, as shown in Figure 11-2.

When Imogen clicks the Analysis button, the application will display a list of analysis commands, as shown in Figure 11-3.

This is our first “submenu” in the application. We could have put all the data analysis functions on the same page as all the other functions, but I think it the program is easier to use if some of the less-popular functions are placed on a different menu. We can create the menus just by creating the schemas for each one as we did in Chapter 10 in the “Build a user interface” section. We can then go back and fill in the functions that are required. Imogen can approve our “empty” menus before we write the code that makes them work.

A screenshot of the fashion shop data analysis application.

Figure 11-2 Fashion Shop data analysis

A screenshot of the fashion shop data analysis application.

Figure 11-3 Fashion Shop Data Analysis menu

Work with array methods

The first three functions requested from Imogen involve sorting the stock data. The items in the Fashion Shop data storage are held in the order that they were added. To meet the first requirement, we want to sort the dataStore array in order of stock level. Sorting is something that a lot of programs need to do, so the JavaScript array type provides a sort method that we can use to sort the array. We just have to tell the sort method how to decide the order of elements during the sort.

We do this by providing a comparison function that compares two values and returns a result that indicates their order. If the result is negative, it means that the first value is “smaller” than the second. If the result is positive, it means that the first value is “larger” than the second. If the result is zero, it means that the two values are the same. We can generate a stock level comparison return value by subtracting one stock level from another.

function stockOrderCompare(a,b){
    return a.stockLevel-b.stockLevel;
}

The function stockOrderCompare takes in two parameters. It gets the stock level values from each item and then returns the result of subtracting one stock level from another. This comparison function can be provided as an argument to the call of the sort method to get the dataStore sorted in this order.

dataStore.sort(stockOrderCompare);

We don’t need to know how the sort method sorts the dataStore any more than we need to know how JavaScript adds two numbers together. One thing that it is useful to know, however, is that the sorting process will not move any StockItem values around in memory. The datastore contains an array of references. We can change the order of the references without having to move anything in memory.

function stockOrderCompare(a, b) {
    return a.stockLevel - b.stockLevel;
}

function doListStockLevel() {
    dataStore.sort(stockOrderCompare);
    createList("Stock Level Order", dataStore);
}

This is the code that produces a list of stock item sorted by stock level. The function doListStockLevel above is called when Imogen selects the option to display the stock sorted in the order of stock level. It sorts the dataStore array and then uses the createList function to display the sorted list.

CODE ANALYSIS

Sorting stock items

The Fashion Shop application in the Ch11 Creating ApplicationsCh11-01 Fashion Shop Stock Sort example folder contains the analysis feature that can be used to display a list of stock items that have been sorted by stock level. You might have some questions about how it works.

Question: What happens when we use the stockItemCompare function as an argument to the sort method?

Answer: A JavaScript function is an object, like lots of other things in JavaScript programs. Objects are managed by references, so the sort method receives a parameter, which is a reference to the stockItemCompare function.

Question: What happens if we try to use the stockItemCompare function on a list of objects that don’t have stockLevel properties?

var names = ["fred", "jim", "ethel"];
names.sort(stockOrderCompare)

Answer: The JavaScript above shows how we would this. The first statement creates an array of strings, which is called names. The seconds statement tries to sort the names using stockOrderCompare as the comparison function. This will not work because the strings in the names array do not have a stockLevel property, but what would it do?

We can work out what would happen by considering what JavaScript does when things go wrong. If we try to access a nonexistent property in an object, JavaScript returns a value of undefined. This means that the stockOrderCompare function would be comparing two undefined values. The result of any calculation involving undefined is the Not a Number (NaN) value. This means that the comparison function returns NaN, which is ignored by the sort method, leaving the array unchanged.

Question: How would I sort an array of names?

Answer: We would have to create a comparison function that compares two strings and returns the required result. JavaScript expressions can be used to determine if one string is “greater than” (further down the alphabet) than another. We can make a stringOrderCompare function.

A screenshot of the function stringOrderCompare.

This function can be used to sort the name array we created earlier. The stringOrderCompare function is declared within the Ch11 Creating ApplicationsCh11-01 Fashion Shop Stock Sort example.

> names.sort(stringOrderCompare)
 ["ethel", "fred", "jim"]
Anonymous functions

We can control how sort behaves by changing the function that is used to perform the comparison, but it is rather unwieldly to have to create the function and then use it as an argument to the call of sort. JavaScript makes it easier to do this by allowing us to declare the comparison function directly in the arguments of the sort call:

dataStore.sort(function(a,b){
    return a.stockLevel-b.stockLevel;
});

This sort does the same job as the original one, but the comparison function is provided as an argument to the call of sort. This type of function declaration is called an anonymous function because it has no name. The function can’t be called by any other code. It has the double advantage of making the program slightly smaller and also binding the comparison directly to the call of sort. With the above code, you don’t have to go and find out what the stockOrderCompare function does. The application in the Ch11 Creating ApplicationsCh11-02 Fashion Shop Simple Function example folder uses this simplified function format to control the sort behavior.

Arrow functions

Arrow functions are a way of making programs even faster to write. Rather than having to type function to create an anonymous function, you can express the function like this:

dataStore.sort((a,b) => { return a.stockLevel - b.stockLevel});

The parameters to the function are given before the arrow (=>), and the block of statements that make up the body of the function is given after the arrow. If your function contains only one statement, you can dispense with both the statement block and the return keyword to make a very short arrow function:

dataStore.sort((a,b) =>  a.stockLevel - b.stockLevel);

The statement above would sort the datastore in ascending order with the lowest stock levels first. What change do you think you would have to make to sort in descending order?

dataStore.sort((a,b) =>  b.stockLevel - a.stockLevel);

This turns out to be a very small change to the program. We just have to reverse the order of the subtraction, as shown in the statement above.

CODE ANALYSIS

Anonymous functions

Anonymous functions and arrow functions are very powerful JavaScript features, but they are also rather confusing when you first see them.

Question: Why is an anonymous function called “anonymous”?

Answer: Because it has no name. Up until now, all the functions and methods that we’ve created have been given names so that we can refer to them in other parts of the program. However, with an anonymous function, I just want to describe a particular behavior to be performed at one point in the program. I could give the behavior a name (as in stringOrderCompare) above, but it is much easier if I can just drop the JavaScript code directly into my application at the point where I want to use it. Programmers sometimes call anonymous functions lambda functions.

Question: Can I call an anonymous function from a different part of my application?

Answer: No. The only place that the code in an anonymous function can be used is the point when it is declared. It can’t be accessed anywhere else because it has no name.

Question: Can an anonymous function call other functions?

Answer: If you wanted to, you could write an anonymous function containing many thousands of lines of code. However, I would not recommend this. I see anonymous functions as just offering a way of dropping a small piece of specific code into a program.

Question: Can I use an anonymous function as an argument to a function?

Answer: Yes, you can. In JavaScript, a function is an object like anything else and can be passed around a program like any other value. In fact, we have already done this. When we use sort, we pass it a function that is to be used to compare two values to be sorted.

Question: Is there any difference between an anonymous function created using the keyword function and one created using the arrow notation?

Answer: We have seen that there are two ways we can describe an anonymous function:

dataStore.sort(function(a,b){
    return a.stockLevel-b.stockLevel;
});

This version makes an anonymous function to perform the comparison in a sort operation. The anonymous function is supplied as an argument to the sort method.

dataStore.sort((a,b) => { return a.stockLevel - b.stockLevel});

This version uses an arrow function to perform the same task. For the task above, you can use function or arrow interchangeably. However, there are differences between how the two anonymous functions work. The most important one is the way that the keyword this works inside an anonymous function. We know about this because we’ve used it to access elements of an object from methods running inside the object. If you want to write an anonymous function that makes use of this to get hold of elements in an enclosing object, you must use the arrow function notation to create the anonymous function. When you use the word function to make an anonymous function, you create a new object that the function code runs inside. Code running inside this kind of anonymous function can only access elements declared inside that function body, which is not usually what you want.

However, code running in the body of an anonymous function created using the arrow notation picks up the value of this from the enclosing object, so the code can get hold of properties from the object. All this is rather complicated, so suffice it to say that if you had an anonymous function running inside a Dress object, and you wanted that function to be able to get hold of the size property of the dress, you should use arrow notation to create the anonymous function.

Sorting by price and value

Sorting in order of price (which is the second data analysis that Imogen wants) can be achieved by changing the comparison function to compare two stock items by their price properties:

The JavaScript code of the function doListPrice is presented. The line of code, datastore.sort((a, b) implies b.price minus a.price) represents the arrow function comparison.

The doListPrice function is a slightly modified version of the doListStockItem function. The final sorting command, which sorts by the amount invested in each type of stock, is slightly more complex because the comparison function needs to work out the total value of each stock item. This value will be the price of an item multiplied by its stock level.

function doListInvestment() {
    dataStore.sort((a,b) =>  (b.price * b.stockLevel) - (a.price * a.stockLevel));
    createList("Investment Order", dataStore);
}

The application in the Ch11 Creating ApplicationsCh11-02 Fashion Shop All Sorts folder contains a version of the Fashion Shop application that implements the sorting behavior using arrow functions.

Use filter to get items with zero stock

The next thing that Imogen wants is a feature that lists all the stock items that have zero stock. We could create a for-loop that will work through the dataStore array and pick out all the items with a stockLevel value of 0. However, there is a much easier way to do this by using another method provided by the array object. We have seen that all arrays provide a sort method that can be used to sort their contents on the basis of a particular comparison function. Arrays also provide other useful methods, including one called filter that works through an array, applying a function that tests each element in the array. If the test evaluates to true, the array element is added to the result.

The JavaScript code of the function doZeroStockItems is presented. The line of code inside the function, var zeroStockList equals datastore.filter((a) implies a.stockLevel double equals o) represents filter the stock.

I’ve written the test as an arrow function that accepts a stockItem (which is what is in the array) and returns true if the stockLevel property of the item is zero. The filter function returns a list that is then displayed by the createList function. As with stockLevel, the zeroStockList contains references to stock items, not the items themselves. The Ch11 Creating ApplicationsCh11-03 Fashion Shop Filter example folder holds a version of the Fashion Shop application that will list the stock items with zero stock levels. We can use this technique to filter the list on any criteria that we like by simply changing the behavior of the selection function.

Use reduce to calculate the total value of the stock

The next feature that Imogen wants is the ability to calculate the total value of all her stock. We could create a for-of loop that works through the datastore array, but there is an easier way to do this by using the reduce method provided by arrays. The reduce method reduces the content of an array to a single value by performing a reduce function on each element in the array and adding up all the results. To make things clearer, I’ll start with a named function before converting it into an arrow function.

function addValueToTotal(total,item){
    return total+(item.stockLevel*item.price);
}

The function addValueToTotal accepts the current total as the first parameter and a reference to a stock item as the second parameter. It calculates the value of the stock item, adds this to the total, and then returns the result. We can use the reduce method in the dataStore array to apply this function to every element in the stock list and work out the total value of the stock:

var total=dataStore.reduce(addValueToTotal, 0);

The first argument to the reduce method is the function that will be called to update the total. The second parameter is the initial total value, in this case, zero. We can convert the addValueToTotal function into an arrow function, in which case, the call of reduce looks like this:

var total = dataStore.reduce(
    (total, item) => total + (item.stockLevel * item.price),
    0);

The application in the Ch11 Creating ApplicationsCh11-04 Fashion Shop Total Value example folder displays the total value of the stock. You can select Total from the Data Analysis menu, and the function displays an alert containing the total stock value. Note that because this program generates new test data each time it is started, you will find that the total value changes each time it is run.

Use map to discount all stock items

You give Imogen the completed version of the software and she is very happy with it—for a while. Then she comes back with another request. She would like to be able to apply a discount to all the items in stock. She would like to be able to drop all the prices by 5 percent. You could do this with a for loop that works through the array, but an array provides a function called map that will apply a given function to every element in the array. To apply a 5 percent discount, you can multiply the price by 0.95.

dataStore.map((item)=>item.price = item.price*0.95);

This single statement will do the job. The map method accepts a function that has a single parameter. The parameter is the item to be worked on. The statement above will drop the price of every item in stock by 5 percent. You can find this example program in the Ch11 Creating ApplicationsCh11-05 Fashion Shop Discount folder.

MAKE SOMETHING HAPPEN

Create extra Fashion Shop functions

Now that you know how to use the map, filter, and reduce methods, you could add some other functions that Imogen might like. Note that for some of them, you might have to use more than one method to achieve the requested result.

  • Add a command that removes a 5 percent discount. (Note that this does not mean that you would add 5 percent to all the prices; you will have to add more than that because the price has been discounted.)

  • Add a command that reduces the price of all items that cost more than $50 by $5. In other words, a dress costing $20 would stay the same price, but a dress costing $60 would be reduced to $55.

  • Add a command that displays the number of items in stock that are colored red.

Read the weather

In this section, we are going to discover how JavaScript programs can fetch and use data from the Internet. You can use this technique to fetch data from a huge range of sources. We are going to create an application that reads weather information from the OpenWeather service at https://openweathermap.org. It is free to create an account on the OpenWeather site and use it to make a limited number of weather requests each day. I’ve also created some “fixed” weather data on the GitHub site for this book that you can use to test your program if you don’t want to register. The weather information is supplied as a JSON-encoded object that arrives in a string of text. The first thing we must investigate is how to fetch a string of text from a server on the Internet.

Fetch data from a server

Until now, all the actions performed by our JavaScript programs have completed very quickly. However, it can sometimes take a while for information to arrive from the Internet, and sometimes a network request can fail completely. A JavaScript application that uses a network connection will have to deal with slow responses and the possibility that a request might fail. A good way to do this is to make the fetch process asynchronous.

Asynchronous operation

There are two ways that I can go shopping. I can go to a shop, select what I want, pay for it, and take it home. My actions are synchronized with the shop because I must wait for the sales assistant to accept my payment and hand over the goods before the shopping is completed. Alternatively, I can email my shopping list to the shop and ask them to deliver my purchases. Now I can do other things, such as dig in the garden while I wait for my shopping to arrive. My actions are not synchronized with the shop, meaning they are asynchronous. If the shop takes a long time to deliver, it just means that I might have more time for gardening (which is actually not a win for me as it turns out—I’d rather stand in a shop than work in the garden). Up until now, when a JavaScript program has asked for something to be done, the action has been performed synchronously. For example, consider this statement.

descriptionPar = document.createElement("p");

This statement is from the Fashion Shop application. It calls the createElement method to create a new document element. When this statement is performed, the application waits for the createElement method to deliver a new document element in the same way that I wait in a shop for my shopping. The createElement method runs very quickly, so the application is not kept waiting long. However, a function that uses a network connection to fetch data from a distant server could take several seconds to complete. This would pause the application for several seconds. The user would not be able to click any buttons on the screen for that time because the browser only allows a JavaScript application to perform one action at once. If you’ve ever had the experience of a web page “locking up” when you try to use it, you will know how bad this feels.

JavaScript promise

To get around this problem, JavaScript introduces the idea of promises. A promise is an object that is associated with a task that a program wants to perform. JavaScript provides a method called fetch, which is used to fetch data from a server. However, the fetch function does not return the data; instead, it returns a promise to deliver the data at some point in the future.

var fetchPromise = fetch('https://www.begintocodewithjavascript.com/weather.html');

The statement above uses fetch to fetch the contents of the file at 'https://www.begintocodewithjavascript.com/weather.html'. This call of fetch returns a promise object. The variable fetchPromise refers to this object. The fetch will start to happen asynchronously. You can think of this as the point in the process where I call the shop and ask them to deliver my shopping.

The fetchPromise object is a link between our application that requested the data and the asynchronous process fetching the data. We set a property on a promise object to identify a function to be called when the promise is kept. A promise object provides a method called then, which accepts a reference to the method to be called when the promise has been kept.

fetchPromise.then(doGotWeatherResponse);

The statement above tells fetchPromise to call the function doGotWeatherResponse when it has finished fetching. So now we need to find out what the doGotWeatherResponse function does.

A screenshot of the function doGotWeatherResponse.

The parameter to a function called when a promise is kept is the result delivered by that promise. In the case of fetch, the parameter is a response object that describes what happened when it tried to fetch the data. It is possible that a network request can fail, so the first thing that the doGotWeatherResponse function does is check the ok property of the response. If this is false, an alert is displayed and the function ends.

If the response is ok, the doGotWeatherResponse function starts the process of getting the data. It uses a “promise-powered” process to obtain the JavaScript object from the JSON in the response.

Get JSON from the network

The json method provided by the response will get the text from the network and convert it from JSON into a JavaScript object. This might take some time. There might be a lot of data to be fetched and decoded, so it makes sense that this process is performed asynchronously, too. The then method of the JSON promise is used to nominate a method called doGotWeatherObject to be called when the weather object has been created from the network.

function doGotWeatherObject (weather) {
  let resultParagraph = document.getElementById('resultParagraph');
  resultParagraph.innerText = "Temp: "+ weather.main.temp;
}

The doGotWeatherObject function gets the temperature information from the weather object and displays it in a paragraph on the page.

{"coord":{"lon":-0.34,"lat":53.74},
 "weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],
 "base":"stations",
 "main":{"temp":18.14,"feels_like":17.24,"temp_min":18,"temp_max":18.33,
         "pressure":1019,"humidity":82},
 "visibility":10000,"wind":{"speed":3.6,"deg":270},
 "clouds":{"all":98},"dt":1599639962,
 "sys":{"type":1,"id":1515,"country":"GB","sunrise":1599629093,"sunset":1599676358},
 "timezone":3600,"id":2645425,"name":"Hull","cod":200}

This is the JSON that describes the weather. You can see that the object contains a main property that contains a temp property that is the temperature value. Note that the temperature is delivered as a value in degrees Celsius, not Fahrenheit. The application in the Ch11 Creating ApplicationsCh11-06 Weather Display example folder contains these functions and will display the weather information when the FETCH button (shown in Figure 11-4) is pressed.

A screenshot of the weather display application.

Figure 11-4 Weather display

Use anonymous functions to simplify promises

The code we have just written will work perfectly well and shows how functions are bound to promises. However, it is also rather long-winded. It turns out that we can use anonymous functions to simplify the code a lot. We can express an anonymous function using the arrow notation. Take a look the “Arrow functions” section above if you want to refresh your understanding of how they work. In this code, we are going to use an arrow function to specify actions to be performed when a promise is fulfilled.

A screenshot of the function doGetWeather.

The doGetWeather function accepts a parameter that gives the network address of the item to be loaded. The function has exactly the same logic as our previous implementation. However, the functions that are to run when the promises are fulfilled are now written as arrow functions that are given as parameters to then. You can find a weather application that uses this function in the Ch11 Creating ApplicationsCh11-07 Weather Arrow Functions sample folder. You can use this code to read JSON objects from different locations by changing the URL string.

Get text from the network

If you just want to read the text from a website rather than the JSON, you can use the text method, which returns a promise to deliver text rather than a JavaScript object. You can see this in use in the application in the Ch11 Creating ApplicationsCh11-08 Weather Text sample folder.

Handle errors in promises

In JavaScript, as in real life, it can sometimes be impossible to fulfil a promise. Perhaps the network is broken, or the text delivered by the server does not contain a valid JSON string. In these situations, the promise will not fulfill by calling the function nominated by then. Instead, a promise can call an error-handling function that has been nominated by a call to the catch method of a promise. The catch function is used in exactly the same way as the then function. It accepts a parameter that describes the error that has occurred.

function doGetWeather(url) {
  fetch(url).then( response => {
    if(!response.ok){
      alert("Fetch failed");
      return;
    }
    response.json().then( weather => {
      let resultParagraph = document.getElementById('resultParagraph');
      resultParagraph.innerText = "Temp: " + weather.main.temp;
    }).catch ( error => alert("Bad JSON: " + error)); // json error handler
  }).catch( error => alert("Bad fetch: " + error)); // fetch error handler
}

You can see the two catches in the doGetWeather function above. They display an alert that contains any error message that was produced when the promise failed.

Use finally to enable a button after a fetch

The weather application we have created makes a fetch request each time the FETCH button is clicked. This can lead to problems. One thing that users quite like to do is repeatedly click a button if they don’t get a response within a second of their first click. In the weather application, this would cause lots of fetch requests. A well-written application would disable the FETCH button once it has been clicked to prevent this behavior. So let’s make our application well-written. A JavaScript program can disable a button by adding a disabled attribute to the button:

The JavaScript code of the fetch button is displayed. The code, let fetchButton equals document.getElementById('fetchButton') finds the button with the ID FetchButton. The line, fetchButton.setAttribute(disabled) disables the button.

These two statements disable a button with the ID fetchButton. Once the fetch has completed, the program can enable the button. We could add code to the then and catch functions to enable the button, but as you know, I hate writing the same code twice. Instead, we can add a finally function to a promise that identifies code to run when the promise has completed, regardless of whether it succeeds. This would guarantee that the FETCH button is enabled once the fetch is complete.

A screenshot of the fetcuButton code.

This is the code that I added to remove the disabled attribute from the FETCH button. You can find it in the sample application in the Ch11 Creating ApplicationsCh11-09 Weather Finally example folder.

CODE ANALYSIS

Investigating promises

The application in the Ch11 Creating ApplicationsCh11-10 Weather Error Handling example folder uses the doGetWeather function above to display the temperature. It also contains two other buttons that activate two broken fetch behaviors. The first attempts to load the weather from a nonexistent network address, and the second loads a file that does not contain JSON data. You can use these to experiment with failed promises.

The weather display application is presented on a browser screen. The title weather with an umbrella icon on the left is displayed on the top. Three buttons fetch, fetch error, and json error is displayed vertically.

Question: What does a promise do again?

Answer: If this is confusing, think of the problem that it is trying to solve. Our program wants to get some information from the network that would take a long time to arrive. So rather than call a method that delivers the information, it calls a method that delivers a promise to perform the action. In other words, rather than saying, “Give me the data from the network,” we say, “Give me a promise object that will be fulfilled when the data has been fetched from the network.”

An application can attach functions to a promise object to be called when the promise is fulfilled (then) or broken (catch). Our program can then continue running without having to wait for the data to arrive. The actions required to deliver on the promise will be performed asynchronously, and at some point in the future, the promise will either be kept or broken, and one of the functions called.

Question: Can I have two promises active at the same time?

Answer: Yes, you can. If you click the FETCH ERROR button in the example above, you will notice that it takes several seconds for the error message to appear. While you are waiting for the error, you can click the FETCH and JSON ERROR buttons to perform their fetch behaviors.

Question: Can I write code of my own that implements promises?

Answer: Yes, you can. We will be doing this in the next chapter when we create a promise that is fulfilled when an image has been loaded into our game.

Question: Why do I need to create a catch behavior for the fetch promise? Can’t I enclose the call of fetch in a try-catch construction to catch any errors that are thrown by fetch?

Answer: If you understand this question and the answer, you can consider yourself a “promise ninja.” JavaScript code can throw an error object when things get tough. This is called an exception. We’ve seen that code working with JSON throws exceptions if it can’t convert a string into a JavaScript object. Look in Chapter 10 in the section “Catching exceptions” to find out how this works. You might think that we could just put a call of fetch inside a try-catch construction in our application to pick up any errors when they occur.

try{
  fetch(url).then( response => {
  // rest of fetch code here
}
catch{
  // handler for errors during fetching
}

The code above shows what you might try to do. However, this would not work because the fetch function only starts the process of fetching network data. Once the process of fetching begins, the fetch function completes, and the application continues out of the enclosing try-catch construction. Errors that arise while getting the data from the server can’t be handled by a try-catch around fetch because the program execution will have left the try-catch block long before the exception is raised.

Question: When would I use finally?

Answer: You use finally when you want to nominate a behavior that must be performed once the promise has ended (by being either fulfilled or broken). This might be to enable a button (which is what we have done) or to tidy up resources that were obtained when the promise started. It is a good idea to get into the habit of using finally, as it is guaranteed to run at the end of the promise, even if code in then or catch functions fail in ways you weren’t expecting.

Node.js

Up until now, all the JavaScript applications that we have written have run inside the browser and used the HTML document to interact with the user. This is fine for creating client applications (meaning applications that fetch data and work with it), but it would be useful to be able to create JavaScript applications that could work as servers that provide data for client applications. In this section, we are going to discover how to use a platform called Node.js to create a server application written in JavaScript. Node.js was created by taking the JavaScript component out of a browser and making it into a freestanding application that can host JavaScript code.

MAKE SOMETHING HAPPEN

Install and test Node.js

Before we can use Node.js, we need to install it on our machine. The application is free. There are versions for Windows PC, macOS, and Linux. Open your browser and go to https://nodejs.org/en/download/.

A screenshot of the node js application installer.

Click the installer for your machine and go through the installation process. Once you have completed the installation, you can start to work with Node.js. The first thing you can do is test that the installation has worked correctly. We can do that by using the terminal in Visual Studio Code. Start Visual Studio Code, open the View menu, and select Terminal. The terminal window will open in the bottom right-hand corner of Visual Studio Code. You use this window to send commands to the operating system of your computer. I’m using a Windows PC, so my commands will be performed by Windows PowerShell. Enter the command node and press Enter.

A screenshot of the terminal window of the visual studio code is presented. The node command is displayed followed by the welcome note of the node js application.

The Node application starts and displays a command prompt. You should find this remarkably familiar. If you enter a JavaScript command, it will be obeyed in the same way as if you were using the console in the Developer View in your browser.

The command prompt of the node application is displayed. A JavaScript code, console.debug(:hello from node.js is entered and the output hello from node.js is displayed in the command prompt.

You can exit from the Node.js command prompt by holding down the CTRL key and pressing D.

The Node.js application provides a way for a computer to run JavaScript applications. If you had entered the command node myprog.js, the command prompt would have executed the JavaScript program in the myprog.js file. Note that because this application is not running in a browser, it can’t use an HTML document to communicate with the user. In other words, Node.js applications can’t use buttons, paragraphs, and all the other elements because there is nowhere for them to be displayed. The job of Node.js applications is to host processes that provide services. It is perfectly possible that the weather service that we have just used is hosted by a Node.js application running on a server connected to the Internet.

Create a web server with Node.js

In Chapter 2 in the “HTML and the World Wide Web” section, we discovered that a web browser uses the HTTP protocol to fetch data from web servers. HTTP describes a way that one program (the browser) can ask for resources from another program (the server). A web server is an application that receives HTTP-formatted requests and generates responses.

Use the HTTP module

The Node.js platform is supplied with a module containing a JavaScript program that can respond to HTTP requests and act as a web server. A module is a package of JavaScript code that we want to use. We can include a module in our application by using the require function to load it. The module is then exposed as an object. The application using the module will then call methods on that object.

var http = require('http');

This statement above creates a variable called http, which refers to an HTTP instance. Now we can use the HTTP object to create a web server. We can do this by calling the createServer method:

A screenshot of the code for creating a web server.

The statement above uses the createServer method supplied by the http object to create a simple web server. The variable server is set to refer to the new server. The createServer method accepts a single argument, which is an arrow function that works on two parameters. This function provides the behavior of the server. It will be called each time a client makes a request of the server. The first parameter to the function describes the request that has been received. The second parameter will hold the response that is to be produced. Our server behavior is implemented by an arrow function that accepts the parameters request and response. The function above ignores the contents of the request and just prepares a response that is a text message 'Hello from Simple Server'. Now that we have our server object, we can make it listen for incoming requests.

server.listen(8080);

The listen method starts the server listening for incoming requests. The listen method is supplied with an argument specifying the port that the server will listen on. Each computer on the Internet can expose a set of numbered ports that other computers can connect to. When a program connects to a machine, it specifies a port that it wants to use. Port number 80 has been set aside for HTTP access, and browsers will use this port unless told otherwise. Our server will listen on port 8080.

CODE ANALYSIS

Using a server

You can find this sample server application in the examples for this chapter. We will not be using this application from the browser; we will start the server running from within Visual Studio code and then view the page that it generates with a browser. Start by opening the Visual Studio Code application and then open simpleServer.js in the Ch11 Creating ApplicationsCh11-11 HTML Server example folder, as shown below:

A screenshot of the visual studio code application is presented. The window shows the code of simpleServer.js. In the left pane of the window, under the open editors, the folder of Ch11 creating applicationCh11-11 HTML server is displayed.

To start the server, you need to run the program in simpleServer.js. Make sure that this file is selected in the file browser as shown above. Open the Run menu and select the Start Debugging option. There are several different ways that Visual Studio Code can run your application, so you will be asked to select the environment you want to use:

A screenshot shows the window of visual studio code. The screen displays the options to select the environment such as chrome (preview), edge: launch, node.js, node.js (preview), VS code extension development (preview), and more.

Click the Node.js option, and the server will start. Now you can open your browser and connect to this server. Because the server is running on your machine, you can use the Internet address localhost. You need to add the port number that you are using to this address, so enter the address localhost:8080 address into the browser and press Enter to open the site.

A screenshot of a browser screen displays the message, hello from simple server.

When you do this, you will see the message from the function that is running inside the server. You might have some questions about what you have just done:

Question: Would this server work on the Internet?

Answer: Yes. You are running both the server (the Node.js program) and the client (the browser) on your PC. However, you could run the server on one machine and access it from the browser on another. If the server machine were on the Internet, it would be possible for distant machines to access the server. One thing to bear in mind, however, is that modern operating systems include a firewall component to manage their network connections. The firewall limits the network services that one machine exposes to another in case malicious programs try to take advantage of too much connectivity. If you want to create a server and allow people access to it, you can use Node.js to do this, but you would have to configure the firewall on the host machine and also take steps to ensure that you provided the services in a secure way.

Question: Does the server program run forever?

Answer: Yes. The call to the listen method will never return. You can use Visual Studio Code to stop the program by clicking the red square box stop button on the right-hand side of the program controls.

A screenshot of the program controls is displayed that shows seven controls. The red square box stop button is shown in the seventh position.

Question: How is the response message from the server constructed?

Answer: The server creates a response object that is sent back to the client. The response tells the client if the server could satisfy the request and contains the data that was requested. The server application performs four statements to create and send the response that is received by the browser:

response.statusCode = 200;

The first statement sets the status code of the response. A status code of 200 tells the browser that the page was found correctly.

response.setHeader('Content-Type', 'text/plain');

The second statement adds an item to the response header by using the setHeader method. A response header can contain items to help the browser deal with the incoming response. Each item is provided as a name-value pair. This statement adds a Content-Type value that tells the browser that this response contains plain text. We could use different types to return things like audio files and images.

response.write('Hello from Simple Server');

The write method writes the content of the page being returned. This server always sends the same text: Hello from Simple Server. It could, instead, send a very large amount of data.

response.end();

The end method tells the server that it can now send the response and the content back to the browser client.

Routing in HTML

In the “Fetching web pages” section in Chapter 2, we saw that the URL expressing the location of a web page contains a host element (the Internet address of the server) and a path element (the path on the host to the item that the client wants to read). The simple server above returns the same text for any path that you use to read from the host. In other words, the URLs http://localhost:8080/index.html and http://localhost:8080/otherpage.html both return the message Hello from Simple Server, as would any other path. The first web server used the path component of a URL to identify the file that the server should open and send to the client. We can improve our simple web server to allow it to respond differently to different paths.

A sample code of the routing in HTML.

The code above implements a server that recognizes two paths: index.html and otherpage.html. If the client tries to access any other path, the sever responds with a “page not found” message. Note that the “page not found” message has a status code of 404 to represent this. The program parses the url property of the request parameter to extract the path that was requested in the URL. This path is then used to control a switch construction that selects the response to be sent. You can find this example server in the example folder. This server program could be expanded to serve a number of different pages.

CODE ANALYSIS

Using multiple paths

You can find the multiple page server in the Ch11 Creating ApplicationsCh11-12 Multi page server example folder. Start Visual Studio Code and from the examples folder, open multiPageServer.js. Ensure that the multiPageServer.js file is selected in the file browser. Now click Run -> Start Debugging to start the application. Select the node.js environment when prompted by Visual Studio Code. Now open your browser and navigate to: http://localhost:8080/index.html.

A screenshot of a browser screen displays the message, hello from index.

The browser will show the text for this URL. Now change the address to http://localhost:8080/otherpage.html and reload the page.

A screenshot of a browser screen displays the message, hello from other page.

The browser will now display the response for the other page. Finally, you can try a missing page. Change the address to http://localhost:8080/missingpage.html and reload.

A screenshot of a browser screen displays the message, page/missingpage.html not found.

If a given path is not recognized, the default element in the switch is performed. This displays the “page not found” message. You might have some questions about this code:

Question: What does the sendResponse function do?

Answer: I hate writing the same code twice. The sendResponse function sends a string as a response to a web request. It saves me from writing the same code to respond to the two different URL paths.

Question: How does the server get the path to the resource that the client has requested?

Answer: The URL is the entire address sent by the browser to the server to request a particular web page. The path part of a URL describes the location of a resource on the server. For example, the server might receive the URL http://robmiles.com/index.html. The path in this URL is /index.html. The URL that was given to the web request is provided as the url property of the response parameter to the method called by createServer. The method called by createServer must extract the path from this URL so that the server can decide what to send back to the browser. The server does this by using the URL module that was loaded at the start of the program.

var url = require('url');

The URL module provides methods that an application can use to work on URL strings. One of the methods that is provided is called parse. The word “parse” means “look through something and extract meaning from it.” The parse method accepts a URL string as an argument.

var parsedUrl = url.parse(request.url);

The parse method creates an object that exposes different parts of the URL as properties. The statement above creates a parsed URL object (called parsedUrl). I use parse because I am lazy and don’t want to have to write JavaScript that extracts the path from the URL string.

var path = parsedUrl.pathname;

Once we have a parsed version of the URL (called parsedUrl), we can extract data from the properties in this object. The pathname property of a parsed object gives the path that the user entered. The statement above gets the path name from the parsed URL and sets the variable path to this name. We are going to use parse again later in this chapter to extract other information from the URL.

Question: What would I need to do if I wanted to add extra “pages” to my server?

Answer: The present version of the server only recognizes the /index.html and /otherpage.html pages. If you want to add other pages such as /aboutpage.html, you just have to add another case to the switch:

case "/aboutpage.html":
  sendResponse(response, "hello from aboutpage.html");
  break;

The example program in the Ch11 Creating ApplicationsCh11-13 Three page server folder serves three pages.

Question: Can I serve HTML pages using this server?

Answer: Yes, you can. However, you need to change the content type from text/plain to text/html so that the browser knows how to process the response.

response.setHeader('Content-Type', 'text/html');

The example program in the Ch11 Creating ApplicationsCh11-14 HTML server folder serves an index page that is HTML.

Question: Is this how you build servers?

Answer: You could build server like this, but it would be hard work. Your server would also have to serve out the image and style sheet files along with the HTML files. I just want to show you how this works so that you can understand how servers work. The Express framework (which we will see later) provides a much quicker way of creating a JavaScript application that will act as a server. However, it uses the same fundamental principles that we have been using.

Use query to add data to a client request

A client can use different path values to select locations on a website, but it would also be useful for the client to be able to send additional data to the server. We can do this by adding a query string to the URL that is sent by the client to the server. You will often see query strings in your browser when you navigate e-commerce sites. A query string starts with a question mark (?) and is then followed by one or more name-value pairs that are separated by the ampersand (&) character:

http://localhost:8080/index.htm?no1=2&no2=3

The URL above contains two query values: no1 (set to the value 2) and no2 (set to the value 3). These query values are sent to the server in the URL string. We could create a server that accepted these values and returned their sum. The server could use the parse method from the url module to extract the query values.

var parsedUrl = url.parse(request.url,true);

We used the url.parse method in the previous section when we needed to extract the resource path from the incoming URL. The call of parse is different in that I’ve added the parameter true to the call, which tells the parse method to parse the query string in the URL.

var queries = parsedUrl.query;

Once I’ve done this, I can extract the value of the two queries from the parsedUr, as shown above. Now my addition program can convert these two query strings into numbers and perform the required calculation:

var no1 = Number(queries.no1);
var no2 = Number(queries.no2);

var result= no1 + no2;

The query values are always sent as strings of text. Our application uses the Number function to convert the query values into numbers. It then calculates their sum. The listing below is the complete source of an “addition” service, which accepts a query containing two numbers and returns their sum.

var http = require('http');
var url = require('url');

var server = http.createServer((request, response) => {

  var parsedUrl = url.parse(request.url,true);
  var queries = parsedUrl.query;

  var no1 = Number(queries.no1);
  var no2 = Number(queries.no2);

  var result= no1 + no2;

  response.writeHead(200, { 'Content-Type': 'text/plain' });
  response.write(String(result));
  response.end();

});

server.listen(8080);

The addition service that we created above does not produce a web page as a result. It returns a string that contains the result of adding two query values together. This kind of service is called a web service. It uses HTTP to transfer messages, but the messages do not contain HTML documents. A more complex web service could return an object described by a string of JSON. We’ve already used one web service, the weather service from openweather.org. Now we know how to create our own web services using JavaScript and Node.js to host them. A Node.js application could also use the file system module fs to open files held on the server and send them as responses.

CODE ANALYSIS

Investigate the addition server

You can find the addition server in the Ch11 Creating ApplicationsCh11-15 Addition Server example folder. Start Visual Studio Code and open additionServer.js in the example folder. Ensure that the file additionServer.js is selected in the file browser. Now use Run -> Start Debugging to start the application. Select the node.js environment when prompted by Visual Studio Code. Now open your browser and navigate to http://localhost:8080/index.html?no1=2&no2=3.

A screenshot of a browser screen displays the number 5.

The server program will work out the result of the calculation (2+3) and return the result. Try changing the values of no1 and no2 and reload the page. The page will update with the new result.

Question: What happens if I don’t supply the query values?

Answer: Try it. Just load the http://localhost:8080/index.html URL and leave off the query.

A screenshot of a browser screen displays the message, NaN.

Accessing a missing property of an object (in other words, trying to get the properties no1 and no2 from a query that does not contain them) will produce the JavaScript value Undefined. Any calculations involving the value Undefined will produce the result Not a number, which when converted to a string, is displayed as NaN.

Question: Can I call the addition service by using fetch in a JavaScript program running in a web page?

Answer: That is a fantastic question, and the answer is yes. This is how most web pages work. We’ve already written an application that used fetch to get information from the weather server. We could write another application that used fetch to call the addition service to perform a calculation.

var url = "http://localhost:8080/docalc.html?no1=2&no2=3";

The JavaScript statement above creates a URL that could be used to call an addition service at docalc.html.

fetch(url).then(response => {
    response.text().then(result => {
        let resultParagraph = document.getElementById('resultParagraph');
        resultParagraph.innerText = "Result: " + result;
    }).catch(error => alert("Bad text: " + error)); // text error handler
}).catch(error => alert("Bad fetch: " + error)); // fetch error handler

This is the JavaScript that performs the fetch to get the result from the service. The service responds with text that is used to set the value of the resultParagraph element on the web page. This code is very similar to the code that was used to read the weather from openweather.org.

You can find this example code at Ch11 Creating ApplicationsCh11-16 Addition Application. Stop the present server running and navigate to the file additionApplication.js in this folder. Use Visual Studio Code to run this program using Node.js and then navigate to http://localhost:8080/index.html in your browser. Click the “Add 2 + 3” button. This will run the fetch above, which will then be displayed on the page.

A screenshot of a browser screen of Ch11-16 addition application.

This is a big moment. Almost all this book has been leading up to this point. You now know how web applications work. The HTML document describes the page, and the JavaScript in the page can do things. If the JavaScript wants to get data from a server, it creates a request and sends it to the server, which decodes the request, generates the result, and sends it back. You should spend some time taking a long hard look at the web page, the server, and the client code until you understand what each part does.

Node package manager

You could use the modules from Node.js to create a complete application server. However, you would have to write a lot of code to decode the requests and build the responses. The good news is that someone has already built a system for creating servers. The system is called Express, and it provides what is called scaffolding, which you can use to construct an application that is powered by HTML pages and web services.

The even better news is that there is also a way of using prebuilt code like Express. It is called node package manager or npm. The npm program is provided with the Node.js installation. You use the npm program to fetch and install prebuilt modules that you can then add into your server programs using the require function that we have seen before. Each application has a configuration file called a manifest that identifies the packages that are to be used by the application. This is all especially useful and extremely powerful, but it is all built on the foundations that you have learned in this chapter. You will create arrow functions that give the behaviors of your server, and you will use promises to ensure that none of your functions block the execution of your program. You can find out how to build your first Express application at http://expressjs.com/en/starter/hello-world.html.

Deploying a Node.js server

The Node.js services that we have created so far have run on our local computer. You would not normally make your computer visible to the Internet so that other people can use your services. Instead, you would host your JavaScript program on an external server. You don’t need to own a server machine. Instead, you can run your JavaScript application as a service in the cloud. You can get started with this for free by creating an Azure account and then using the App Service Extension for Visual Studio Code to configure and deploy the service that you have created. You can find out more at https://azure.microsoft.com/en-us/develop/nodejs/.

What you have learned

In this chapter, you learned how JavaScript code can be embedded directly in a program as anonymous functions and how the arrow notation makes this easier. You also discovered how programs can interact with the network and how the JavaScript promise mechanism allows the applications to contain asynchronous execution. Finally, you have investigated the Node.js platform that allows JavaScript programs to run on a computer and provide services for JavaScript client applications running in a browser.

  1. JavaScript arrays provide a sort behavior that will sort their content. We used this to sort the Fashion Shop stock list in order of stock level. The order of a sort is determined by a comparison function that is supplied to the sort behavior. The comparison function accepts two parameters, which are array elements. It compares the elements in some way and returns a value that is negative, zero, or positive, depending on the order in which they are to be sorted. The comparison function can be supplied as a named function or as an anonymous function directly as an argument.

  2. An anonymous function can be expressed using an arrow notation in which the parameter list and body of the function are separated by an arrow operator (=>). If the body of the arrow function is a single statement, it does not need to be enclosed in a block, and if the single statement returns a value, the return keyword can be omitted.

  3. JavaScript arrays provide a filter behavior. We used filter to create a list of Fashion Shop stock items with zero stock. The filter behavior returns another array containing selected elements. The behavior of the filter is determined by a filter function that is supplied to the filter behavior. The filter function accepts a single parameter and returns true if the value of that parameter means that it should be included in the filtered results.

  4. JavaScript arrays provide a reduce behavior, which can convert an array into a single value. We used reduce to calculate the total value of all the stock in the Fashion Shop. The reduce behavior is provided with a function that accepts two parameters: the current total and a reference to an element in the array. The function calculates the new total by adding the value for the given element (in our case, the price of the element multiplied by the number in stock) to the total. The reduce behavior on an array is also provided with a starting value (which is usually 0) for the total.

  5. JavaScript arrays provide a map behavior that applies a given function to every element in the array. We used this to apply a sale discount to the price of every item for sale in the Fashion Shop. The map behavior is provided with a function that accepts a single parameter—the element to be updated.

  6. A JavaScript application running inside a web browser can consume the contents of a web service that is located at a particular address on the Internet. The web service can provide the data in the form of a JSON object, which can be decoded by the client application and displayed to the user. We used this create an application that read weather information from a server at openweather.org.

  7. Some JavaScript operations, such as the fetch function that reads a message from a network, can take a noticeable time to complete. It is important that time-consuming operations such as fetch do not cause an active application to pause in a noticeable way. If a button-click handler in a web page takes a long time to complete, the web page would appear to have “locked up,” and the user would not be able to interact with it. JavaScript allows long-running operations (such as fetching from a network) to be performed asynchronously.

  8. The JavaScript promise mechanism allows a programmer to invoke operations that will be performed asynchronously. A promise exposes a then property that can be used to specify JavaScript code that will be performed when the asynchronous behavior “promised” to the calling application has completed. A promise also exposes a catch property that specifies code to be performed if the asynchronous operation fails.

  9. JavaScript promise operations can be chained together. This allows an action that processes data delivered by a promise to return a promise to produce the processed data. We used this to allow an asynchronous JSON decoder to run directly after a fetch operation has completed.

  10. A JavaScript promise exposes a finally property that can be used to specify code that will be run whether the promise is “kept” (the operation completed successfully) or “broken” (the operation could not be completed). We used the finally property to run code that enabled a button in the HTML document.

  11. The Node.js framework allows a computer to run JavaScript programs without opening HTML files in the browser. The Node application contains a JavaScript runtime environment that will run JavaScript code. Code running inside Node.js cannot interact with the user via an HTML document (because there is no document), but it can provide JavaScript powered services for other applications. Node.js can be downloaded and installed for free on most computing platforms. (It is an open-source application.)

  12. You can run Node (the program that implements the Node.js framework) from the command line. Node can provide a console like that in the browser Developer View, or it can open files containing JavaScript code and run them. You can run Node from the command prompt within Visual Studio Code.

  13. The Node.js framework is supplied with a number of modules. The require function is used in an application to load a module and make it available for use in a program. One such module is the http module, which can be used to create web servers and clients.

  14. The http module in Node.js can be used to create a server. The server will run on a computer and accept HyperText Transport Protocol (HTTP)–formatted messages that will request services from that computer. Clients making requests of the server will use a uniform resource locator (URL) to specify the network address of the server, the port number (if the port is not port 80), and the path to the resource on the server. The local server that we used for the demonstration code has this address: http://localhost:8080/index.html.

  15. The http.createServer method used to create a server is called with a single argument, which is the service function for that server. The service function takes two parameters: the request and the response. The request parameter contains a description of the request received from the browser, and the response parameter is an object that can be used to build the response.

  16. The http.listen method is called with a parameter of the port number that the sever is to listen on. The listen method will call the service function each time a remote client makes a request of the server. The listen method will never stop running; it will repeatedly respond to requests. Our first server ignored the content of the request parameter and sent a simple text response. This response was sent each time a browser client navigated to the server.

  17. A response contains a status code (which is 200 for success), a header (which is content type information), and the response text (which is the data that the server is sending to the client).

  18. The service function can parse the request and obtain the path component of the URL that was specified by the client. The service function can then serve up different responses for different paths.

  19. A URL can also contain query data which is made up of name-value pairs which can be used by the server function to determine the response that is to be provided. We created an addition server that used a query data string containing values for two numbers to be added together. Query data is one way that a client can communicate with a server.

  20. A JavaScript program running inside a browser can use the fetch function to interact via query data with services provided by a server.

  21. A single Node.js application can both serve up HTML pages for a browser and respond to queries. This is the basis by which many web applications work.

  22. The Node package manager provides a way for prewritten JavaScript frameworks to be incorporated into applications. The Express framework provides the “scaffolding” that can be used to create JavaScript-powered applications that run from a server.

Here are some questions that you might like to ponder about what we have learned in this chapter:

What is an anonymous function?

An anonymous function is one that has no name. That’s probably not a useful answer, though. If you want to call a function by name, you can create it with a name. If you just want some code to give to another part of your application, you can just pass the code itself over. The sort method for an array needs to be given a behavior that tells it how to put items in order. We could pass the sort method the name of a function to call. Alternatively, we can provide the code itself in the form of an anonymous function.

Can I reuse code in an anonymous function?

No. Code in an anonymous function exists in one place in the code and is used from there. If you want to use a behavior in different parts of your program, you can make a named function and then call it by name every time you want to use it in your code.

Are there any performance advantages to using anonymous functions?

No. All that happens is that the JavaScript system places the code that implements the function in particular place in memory and then uses that address to call it. An anonymous function is called in exactly the same way as any other when the program actually runs.

Are there any performance advantages to using arrow functions to denote anonymous functions?

No. The arrow function was created to make it easier for programmers, not to make the program itself run more quickly.

Is there such a thing as an anonymous method?

No. A method will always have a name because it is named element in an object.

What does it mean if a function returns a promise?

A promise is an object that represents a statement of intent. At some point in the future, the code that implements the promise will run and either work (the promise is fulfilled, and the function specified by then is called) or fail (the promise is broken, and the function specified by catch is called). The code to implement the promise will run asynchronously, allowing the code that requested the action to continue running.

Can a promise have multiple then behaviors?

Yes, it can. You use the then method to tell a promise what to do when the promise is fulfilled. You can call then multiple times on a given promise. Each call of then can specify code to run when the promise is fulfilled. When the promise is fulfilled, the then functions will be called in the order that they were assigned.

Can multiple promises be active at one time?

Yes, they can. As an example, a program might fire off several successive calls to fetch to obtain multiple resources from the network. Note that because each call is asynchronous, the program has no idea which of the promises will be fulfilled first. It might be that the most-recent fetch returns its result first. It is the job of the program that requested the promises to synchronize the responses.

What happens if a promise is never kept?

If a promise is never kept, the then, catch, and finally functions will never be called by the promise.

What is the difference between a request and a response in a web server implementation using HTTP?

The request describes what is being asked for by the browser. It is a lump of data that describes the HTTP request. The request contains the URL entered so that the server can determine the path to the resource to be returned. The URL may also contain query items. The response object is used to build the response from the server. The response contains the status code for the response (200 means “worked okay”), header information, and the data to be sent back. The job of the server function is to use the request information to work out what is required and then put that information into a response to be sent back to the client.

How many query items can a URL contain?

A URL can contain many query items and each item can be quite long. If you look at the URL in the browser of an e-commerce site such as Amazon, you will see that the address can contain many query items. These are used by the server to maintain a session with the browser connection.

Can a Node.js application display graphics for the user?

Not directly. The Node.js platform will run JavaScript applications, but it does not maintain an HTML document for the application to communicate with the user. However, a web application running on a machine can be sent HTML documents by an application running under Node.js. The final example application, Ch11 Creating ApplicationsCh11-16 Addition Application, does this.

Can an HTML server application create a “session” with a web client?

HTTP is described as stateless. Each request made by a web client is “atomic.” Once it has completed, the server forgets about it. If you want to create a “session” with a server, the application must provide data to the server program to identify the session it is part of. One way to do this is for code in the browser to use query string values to identify the session.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
184.72.135.210