|Written by Ian Elliot|
|Monday, 15 May 2017|
Page 1 of 4
Available as a Book:
Buy from Amazon.
Events, Async & AJAX
buy from Amazon
So how can an event handler that cannot avoid doing something that takes a long time keep the UI responsive?
Using a single threaded event based UI forces us to introduce the idea of asynchronous tasks or functions.
Ordinarily a function will return when it has finished running its code. This is generally called a synchronous or blocking function because it blocks the UI thread until it is complete. To avoid blocking the UI thread we need to invent non-blocking functions that return as soon as possible and nearly always before they have completed their task.
A non-blocking function sets a process in motion and then returns to the calling program.
This allows the calling program to do whatever it has to and then return to allow the thread to process the UI.
This all seems very nice but you can see that there is a problem and it is a big problem.
The non-blocking function returns before it has completed and this means that the event handler returns before it has the result of the call, so the job isn't done. We need to activate some code to process the results of the non-blocking function.
How are we to do this?
The standard solution is to provide a callback function to the non-blocking function. A callback is a function that the non-blocking process calls when it has really finished its task.
A callback is like an event handler which fires when the non-blocking function complete its task.
You can even implement a callback so that it looks exactly like an event.
For example, consider the Ajax get function, more about which in later chapters, which simply downloads the specified file from the server:
In this case the callback is an anonymous function that simply displays the data stored in the file. Notice that if the get was a blocking function the code would read:
and there would be no need for a function of any sort.
It is easy, but a little messy, to convert this to an event on an object. To do this we need an object with a new get function that will download the specified url and then raise the loaded event:
Notice that now the callback function simply fires the loaded event with data as the custom data object.
To use this new get method on the new ajax object all we have to do is register an event handler and call the method:
Now when the file has downloaded the loaded event is fired on the ajax object and the event handler is called.
The Problem With Asynchronous
Callbacks may be like event handlers, but they way that they occur in code makes them a very different proposition. Event handlers are in the main easy to write and cause few problems, but callbacks have some serious problems. The reason for this difference is that event handlers are set up by code that has no interest in their results. When you set a button's click handler the code that sets it generally doesn't want to interact with the click handler later in time when a click occurs. It's a set and forget operation. In other words, event handlers are usually fairly closed pieces of code that don't depend on anything else.
Callbacks, on the other hand, generally do something that the code that sets them up cares about. Generally you want to download a file and process the data it contains. In an ideal world the download would complete and then the code would continue on its way to process the file. When you have to use a callback this isn't the way it happens - the process is initiated and the code that started it comes to an end; only later does the callback activate and the process is completed elsewhere.
This is more difficult.
You will hear lots of explanations of the problem of asynchronous code along the lines of "callback hell", and the "callback pyramid of doom". These are problems but they arise from taking particular approaches to asynchronous programming.
The first problem is that raw asynchronous programming distorts the intended flow of control.
In a synchronous program you might write
and you can expect A to load before B which loads before C.
As soon as you convert these to async operations you can't be sure what order things are done in unless you adopt the callback cascade:
where each function accepts a callback as its parameter.
The callback approach to async turns sequential default flow of control into nested function calls. But keep in mind that the callback approach is just one of many. Because it is so widely used, there is a tendency to think that a callback is the only way to deal with asynchronous code.
|Last Updated ( Tuesday, 16 May 2017 )|