Implementing Interrupts and Timeouts - Advanced JavaScript - JavaScript, 20 Lessons to Successful Web Development (2015)

JavaScript, 20 Lessons to Successful Web Development (2015)

PART II Advanced JavaScript

LESSON 19 Implementing Interrupts and Timeouts

image

To view the accompanying video for this lesson, please visit mhprofessional.com/nixonjavascript/.

To allow computers to do more than one thing at a time, they use a technique called interrupts, in which each process is given a few cycles of processor time in turn. At any one time only one process is active, but because the computer switches between them really quickly, they appear to be all running simultaneously.

Apart from supporting multitasking, interrupts are perfect for cutting down on unresponsive behavior. For example, if you have to wait while a program does something such as fetch some data from a web server, it can be very annoying, but with timeouts, a task can be initiated, which then runs under interrupts as a background program, to then report back when it has completed, leaving you or the foreground task to get on with the current work in hand.

JavaScript supports both types of interrupts, enabling you to run multiple programs at a time, and to pass off tasks to programs to complete in the background, and it’s all actually quite easy to implement.

Using Interrupts

JavaScript provides access to interrupts, a method by which you can ask the browser to call your code after a set period of time, or even to keep calling it at specified intervals. This provides you with a means of handling background tasks such as Ajax (Asynchronous JavaScript And XML) communications (covered next), or even things like animating web elements.

To accomplish this, there are two types of interrupts, setTimeout() and setInterval(), both of which have the accompanying functions clearTimeout() and clearInterval()for turning them off again.

Using setTimeout()

When you call setTimeout(), you pass it some JavaScript code or the name of a function and the value in milliseconds representing how long to wait before the code should be executed, like this:

image

Figure 19-1 shows this code (saved as settimeout.htm in the companion archive) being loaded into a browser.

image

FIGURE 19-1 The alert pops up after the specified delay.

In case you are wondering, you cannot simply supply the alert() function as a setTimeout() argument because the alert() would be executed immediately. Only when you provide either an anonymous function or a function name without parentheses can you safely pass that function to be called later.

Passing a String

There is an exception to this, though, because you can pass a string value to the setTimeout() function, and then it will not be executed until the correct time, like this:

setTimeout(″alert(’Hello!’)″, 5000)

In fact, you can place as many lines of JavaScript code as you like, if you place a semicolon after each statement, like this (saved as settimeout2.htm in the accompanying archive):

setTimeout(″document.write(′Starting′); alert(′Hello!′)″, 5000)

image

I tend to prefer using separate functions in interrupts so that I can modify the function if necessary, without having to alter the code that generates the interrupt.

Repeating Timeouts

One technique some programmers use to provide repeating interrupts with setTimeout() is to call the setTimeout() function from the code called by it, as with the following, which will initiate a never-ending loop of alert windows:

image

Now the alert will pop up every 5 seconds, so if you try out this code (settimeout3 .htm in the accompanying archive), you’ll need to click the Home button in your browser to snap out of the loop.

Cancelling a Timeout

Once a timeout has been set up, you cannot cancel it unless you previously saved the value returned from the initial call to setTimeout(), like this:

handle = setTimeout(DoThis, 5000)

Armed with the value in handle, you can now cancel the interrupt at any point up until its due time, like this:

clearTimeout(handle)

When you do this, the interrupt is completely forgotten about and the code assigned to it will not get executed. The file cleartimeout.htm in the accompanying archive illustrates this in action.

Using setInterval()

An easier way to set up regular interrupts is to use the setInterval() function. It works in just the same way, except that after popping up after the interval you specify in milliseconds, it will do so again after that interval passes, and so on forever, unless you cancel it.

Let’s use this function to display a simple clock in the browser, like this (using liberal whitespace for neat layout):

image

Every time ShowTime() is called, it sets the object date to the current date and time with a call to Date():

var date = new Date()

Then the innerHTML property of the object passed to ShowTime() (namely object) is set to the current time in hours, minutes, and seconds, as determined by a call to toTimeString(). This returns a string such as 09:17:12 UTC+0530, which is then truncated to just the first eight characters with a call to the substr() function:

object.innerHTML = date.toTimeString().substr(0, 8)

Using ShowTime()

To use this function, you first have to create an object whose innerHTML property will be used for displaying the time, like this HTML:

The time is: <span id=′time’>00:00:00</span>

Then, from a <script> section of code, all you have to do is place a call to the setInterval() function, like this:

setInterval(″ShowTime(O(’time’))″, 1000)

This statement assumes you have loaded in the O() function by including the mainfunctions.js file. It then passes a string to setInterval(), containing the following statement, which is set to execute once a second (every 1000 milliseconds):

ShowTime(O(’time’))

Figure 19-2 shows this code (from setinterval.htm in the accompanying archive) running in a browser.

image

FIGURE 19-2 A simple clock created with setInterval()

Cancelling an Interval

To stop the repeating intervals previously set up from a call to setInterval(), you must previously have made a note of the interval’s handle (also called the interval ID—not to be confused with an element ID), like this:

handle = setInterval(″ShowTime(O(’time’))″, 1000)

Now you can stop the clock at any time by issuing the following call:

clearInterval(handle)

You can even set up a timer to stop the clock after a certain amount of time, like this:

setTimeout(″clearInterval(handle)″, 10000)

This statement will issue an interrupt in 10 seconds that will clear the repeating intervals. You can try this for yourself with the file setinterval2.htm in the accompanying archive.

A Simple Animation

By combining a few CSS properties with a repeating interrupt, you can produce all manner of animations and effects. For example, Figure 19-3 moves a square shape across the top of a browser, all the time ballooning up in size, before starting all over again.

image

FIGURE 19-3 A simple animation (the current frame plus previous ones fading out)

The code used to produce the figure is as follows (and is saved as animation.htm in the accompanying archive):

image

image

In the head of the document, the CSS ID of box is set to a background color of red with a 1-pixel black border, and its position is set to absolute so that it is allowed to be moved around in the browser.

Then in the Animate() function, the global variables SIZE and LEFT are continuously updated and then applied to the width, height, and left style attributes of the box object (adding px after each to specify that the values are in pixels), thus animating it at a frequency of once every 30 milliseconds.

image

I’m sure you can think of some other attributes you could animate and will have fun playing with this example.

Web Workers

HTML5 web workers provide an even easier way for browsers to run multiple JavaScript threads in the background that can pass messages to each other, in much the same manner as the threads running in an operating system. You simply call up a new worker script that will sit there in the background either waiting for messages to be sent to it, which it will then act upon, or working away at something and sending messages only whenever it has any information to report.

This aims at achieving a significant speed increase over regular background JavaScripts, although getting to grips with programming them is likely to require a steep rather than gradual learning curve. Here’s how to find out if a browser supports web workers:

image

This script simply alerts you as to whether or not web workers are supported by the browser you are using. Once you have determined that the browser will use them, you can run code such as the following, which calculates prime numbers in the background (saved as webworkers.htm in the accompanying archive):

image

This script displays some text and creates an element with the id of result into which the highest prime number found so far is continuously written. This is achieved by creating the new object called worker by calling the Worker() function, and passing it the name of an external JavaScript file called worker.js (explained shortly).

The onmessage event of the worker object is then attached to by the code. This triggers only when there is a new message to display, and the code that is called copies the data in event.data into the innerHTML property of the result element. After the code exits, it will not be called again until another message is ready to display.

The code that does the prime number calculation is saved separately in the worker.js, and looks like this:

image

This is a simple iterative piece of code that increases the value of n, starting from 1. After each increase, all values of 2 up to the square root of n are tested to see whether they are a factor of n. If any of them is, then n cannot be prime and so the continue keyword forces execution to go back to the start of the search: loop to see whether n + 1 is prime, and so on.

But if n is found to have no factors, it is prime and the continue keyword is not encountered, so program flow drops through to the postMessage() call, which posts the value n, creating an onmessage event on the worker object in the preceding code. The result of running this code is a line of text at the top of the browser that continuously updates and looks like this:

The highest prime number discovered so far is: 42737

Working together, an HTML page and associated JavaScript file can work away in the background, performing all manner of tasks, something that was achievable in the past only by manually creating events to run the code a few instructions at a time before returning to allow the web page to have some processor cycles, after which the event is then created to let the program code run a few more cycles, and so on.

As you might imagine, the old way is rather tricky and can be cumbersome. It can also mess with smooth animations on your web page if you don’t get the event timings and time sharing exactly right. But with web workers, you can forget all about these things and simply place your background code into its own file, and just ensure the code calls the postMessage() function whenever it has something to say.

For full details on the web worker specifications, you can check out the official website at tinyurl.com/webworkerspecs.

Summary

This lesson has given you the tools you need to extend your web pages into powerful web applications, and to create seamless, behind-the-scenes programs to complete tasks without interrupting the smooth flow of the foreground process.

In the final lesson we’ll take this one step further and round off your introduction to JavaScript by looking at how to implement background communication between a web server and web browser using Ajax.

Self-Test Questions

Using these questions, test how much you have learned in this lesson. If you don’t know an answer, go back and reread the relevant section until your knowledge is complete. You can find the answers in Appendix A.

1. Which function do you call to set an interrupt to occur at a specific time in the future?

2. Which function do you call to set interrupts to occur at repeating intervals?

3. How can you cancel a timeout from occurring?

4. How can you cancel repeating interrupts from occurring?

5. What measurement of time is used for timeouts and intervals?

6. How can you test whether a browser supports web workers?

7. How do you create a new web worker?

8. What event is used by web workers to communicate with a calling process?

9. What function is used to send a message to a calling process?

10. Which property of the worker event contains the posted message?