JavaScript Async - Events
Written by Ian Elliot   
Monday, 21 August 2017
Article Index
JavaScript Async - Events
Bubbling & Controlling Events
True Asynchronous Events

JavaScript is an asynchronous language - what exactly does this mean? We delve into events to find out how this basic behavior affects the way JavaScript works and how best to think about it. Asynchronous code is a big topic, but events are where it all starts.

Now Available as a Book:

 JavaScript Async

cover

You can buy it from: Amazon

Contents

  1. Modern JavaScript (Book Only)
  2. Events,Standard & Custom
  3. The Callback
      extract - The Callback & The Controller
  4. Custom Async - setTimeout, sendMessage & yield
      extract - Custom Async
      extract - Avoiding State With Yield 
  5. Worker Threads
      extract - Basic Worker ***NEW
      extract - Advanced Worker Threads 
  6. Consuming Promises 
  7. Producing Promises
      extract - The Revealing Constructor Pattern
     
    extract - Returning Promises
     
    extract - Composing Promises
  8. The Dispatch Queue
      extract - Microtasks
  9. Async & Await
      extract -  Basic Async & Await
      extract -  DoEvents & Microtasks
  10. Fetch, Cache & Service Worker
      extract - Fetch  
      extract - Cache
     
    extract -  Service Workers

 

Asynchronous programming has become more or less the norm in every language at some level or another, but JavaScript almost makes it a basic principle.

JavaScript is essentially an asynchronous language - until recently it was even a single threaded asynchronous language. This is something that affects the way JavaScript works and the very nature of JavaScript code and the difficulties there are in creating it. 

Put simply there are various features of JavaScript that only make good sense if the language is used in an asynchronous environment.

So what exactly is this "asynchronous" behavior all about?

The Workings Of Async - The Dispatch Queue

JavaScript can be considered to be a single threaded language.

A thread in this case means thread of execution. A typical machine will have many threads of execution all managed by the operating system. This is how a machine can seem to be doing more than one thing at a time.

A JavaScript program running in a single web page has just one thread of execution - the UI thread.  

The reason it is generally called the UI thread is that its sole purpose in life is to look after the User Interface. The UI thread simply responds to events generated by the UI. 

A JavaScript program is essentially a collection of event handlers flying in formation.

What happens is that the dispatcher maintains a queue of requests generated by UI events. The UI thread takes a request from the front of the queue and runs the code associated with the event. When the event code completes the UI thread returns to the queue and deals with another request. This continues until the queue is empty and all of the events have been dealt with. The UI thread then just waits for an event to occur.

DIAGRAM IN BOOK

if you have understood this simple dispatcher mechanism you should be able to understand a great deal of otherwise strange behavior. 

For example if you write an event handler that takes a long time to complete then the user interface will appear to freeze because the UI thread cannot process any more events. 

In fact the for a responsive UI what you really need is for the UI thread to be idle most of the time just waiting for an event to occur. When ever you are actually making use of the UI thread within an event handler then the user interface is frozen. 

The ideal JavaScript program does nothing but wait for a UI event.

The big problem is that JavaScript is single threaded and the only thread you have to do any work is the UI thread - so you have to find ways of using it that don't make the user interface freeze up. 

Note: HTML 5 introduced the worker thread which effectively makes JavaScript multi-threaded. At the moment however most JavaScript programs don't make use of worker threads and the technology is relatively young. Even if you do decide to use worker threads it is still important to understand the single threaded nature of the UI - worker threads don't change this.

In the future it makes sense to use an architecture that puts all of the real work on a worker thread and leave the UI thread to just interact with the user. This is covered in a later chapter but you should not underestimate the subtle difficulties in writing reliable multithreaded programs. Indeed this is the reason that most UIs are single threaded. There have been attempts in the past to create a UI framework that allows multiple threads to work with it but it has always proved harder than you might imagine.

As a result JavaScript and HTML, in line with most UI frameworks, limit access to the UI to a single thread.

That is you cannot have one thread respond to one button click and another thread responding to another click. In the JavaScript UI things happen one at a time. 

Events

The key idea is that the natural state of the UI thread is doing nothing.

It really should only burst into life to do something in response to an event and get back to waiting for the next event as soon as possible.

This raises the question of what exactly an event is?

The simple answer is that mostly event generation has nothing much to do with JavaScript it is part of the definition of the DOM - the Document Object Model which is the code representation of the UI generated by the HTML.

The DOM isn't part of JavaScript and it is only available when JavaScript is running in a browser. Other environments provide events in slightly different ways but mostly they looks like the events that the DOM generates.The DOM may not be part of JavaScript but everyone regards it as the standard way to do things.

For example, when the user clicks on a button say the button click event is added to the dispatcher's queue. The details of the event are also stored in the queue as an event object. The event object has a range of properties which can be used by the event handler to find out which UI element generated the event and other details. What is stored in the event object depends on the event that occurred and to an extent on the particular browser being used.

When the dispatcher is free it takes the event at the head of the queue and calls the event handler passing it the event object. The event handler responds to the event by doing something appropriate and perhaps using the information about the event stored in the event object.

Notice that when an event handler is running nothing else can happen. The event handler will run until it yields the UI thread by performing a return. Events that happen while an event handler is running are added to the dispatcher's queue but they have to wait their turn for the UI thread to run them.

JavaScript programming can be seen as mostly creating event handlers and registering them with objects that can generate events. You could say that the only purpose of a JavaScript function object is to respond to the user but this is going a bit too far. Events however have to be seen as driving most applications with code being run in response to the events generated by the DOM.  

How do you register a function to an event?

This used to be a problem because different browsers implemented event handling in different ways but today there is just one standard way of doing the job.

If you need to support older browsers then use jQuery which provides a browser independent way of working with events.

In HTML you can set an event handler on an element using the well known "on" properties - e.g.

<button onclick="myEventHandler" ...

You can also add and event handler by setting the property in code:

document.getElementById("myButton")
                  .onclick=function(e){...}

Not all events have on properties and therefore cannot be set in this way. Also you can only set a single event hanlder. Assigning another function to the "on" property simply overwrites the previous value.

In code the modern way of doing the same job is to use the addEventListener method to register the event handler to the target. The target keeps a list of event listeners and so isn't restricted to juse one.

For example:

button1.addEventListener("click",myEventHandler);

will result in myEventHandler being called when the user clicks the button. Notice that while the HTML needs a string which provides the event handlers name the addEventListener uses the reference to the function object. The first parameter specifies the event as a string.

A good source of information on what event names you can use can be found in MDN - https://developer.mozilla.org/en-US/docs/Web/Events.

One small point that is often overlooked is that an event source can have more than one event handler registered with it using addEventListener.  It is customary to call event handlers added using addEventListener "event listeners", but the term "event handler" can be used for anything that responds to an event.

For example:

button1.addEventListener("click",myEventHandler1);
button1.addEventListener("click",myEventHandler2);

function myEventHandler1(e){
 alert("event1");
}

function myEventHandler2(e){
 alert("event2");
}

When the button is clicked you will see two alerts, one per event handler. Notice that there is no guarantee as to the order in which event handlers are called. 

Why would you register multiple event handlers?

In many cases it doesn't make sense to use more than on event handler. The reason is that an event occurs and it is clear and simple what should happen. The user clicks a Save button and the click event should result in a click event handler being called that saves the data. One event - one handler. However there are times when this isn't the case because an event is associated with multiple unrelated logical actions. You might have a Save button that saves the data and incidentally shows the user an ad. In this case it makes sense to keep the functions separate. However notice that there is no way to make sure that the ad is shown before the save or vice versa. If you demand determinacy then you need to use jQuery's reimplemenation of JavaScript events - see Just jQuery: Events,Async & Ajax.

You can also remove an event handler using:

removeEventListener(type,function,useCapture)

notice that the type and function have to match exactly the event handler added. 

Removing event handlers is something of a problem. There is currently no way to get a list of events that are registered to an object. This is fixed in DOM 3 but at the moment this isn't implemented in any of the modern browsers. If you want to remove event handlers you have to keep track of them yourself and this means not using anonymous functions which are currently difficult if not impossible to remove.

 <ASIN:1871962528>

<ASIN:1871962501>



Last Updated ( Monday, 21 August 2017 )