While Ajax has become mainstream, user interfaces still cannot boast of instant responsiveness to user actions. The reason is that many developers are accustomed to thinking in terms of "request / response" and think that the UI should work in parallel with the front-end, waiting for a response from the server to each request. But why not update the interface before the answer came?
The problem is quite acute, because speed is a critical characteristic of the UI. For example, according to Amazon, a delay in loading a page of only 0.1 seconds leads to a decrease in store turnover by 1%. According to Google, a delay of 0.5 seconds reduces the number of search queries by 20%.
Ruby / JavaScript developer Alex MacCaw of Twitter
offers a logical solution: extend Ajax principles not only to the front end, but also to the user interface. He developed the appropriate framework for what is called AUI (Asynchronous User Interface).
According to McCaw, the interface does not have to wait for the server to respond, because it leads to completely unnecessary delays. For example, what does the interface expect in this screenshot, why does it block user actions?
')
After all, the letter can be safely sent in the background, and the user does not have to wait for the message about the successful sending. Of course, with the exception of those rare cases when you send a
really important letter and want to know for sure that it has gone to the addressee. But in reality this is an illusion of reliability, because the sender's server cannot guarantee that the addressee will indeed receive this letter.
Anyway, the delayed interface example in Gmail refers to hundreds and thousands of other web applications where the user interface waits for a response from the server before allowing any action to be taken.
Alex McCaw developed the
Spine JavaScript framework. It implements a conceptually new approach in which the UI works independently of the server part of the application, that is, asynchronously.
As a result, you can significantly increase the speed of UI. Alex gives an example of a simple
web application where you can evaluate the speed of Spine (ruby backend). Note that all actions are performed instantly, while Ajax REST calls are sent in the background.
To implement an asynchronous UI, you need to follow three basic principles:
- Migrating state and rendering to client side
- Intelligent data preloading
- Asynchronous communication with the server
On the first two points, Alex McCaw refers everyone to his book
Javascript Web Applications , and the third point explains in more detail using the following example. Suppose a user wants to change the title of a page while working with a CMS. When working in an asynchronous UI, he can do it instantly and continue working with the application, without waiting for a response from the server. In Spine terminology, we are dealing with a
model called
Page
. When changing the model name in the controller, the following happens:
page = Page.find(1) page.name = "Hello World" page.save()
As soon as the
save()
call occurs, Spine performs the following actions:
- Checking callbacks and saving changes to memory
- Change event and user interface update
- Sending an Ajax PUT request to the server with a message about the change
Note that the Ajax request is sent to the server
after the user interface is updated.
Since Alex McCaw has been working with such technologies for a long time, he worked out various synchronization with the server in order to avoid mistakes. For example, he implemented client-side data validation. Of course, this is not always possible (for example, checking the uniqueness of an attribute requires access to the database). There is no simple solution, so the discussion continues. It is easier to deal with network errors: to avoid closing the browser before sending a request to the server, it is enough to monitor the occurrence of the
window.onbeforeunload
event and notify the user if there is an unsent request.
window.onbeforeunload = -> if Spine.Ajax.pending '''Data is still being sent to the server; you may lose unsaved changes if you close the page.'''
Similarly, if the server returns an error, it can be passed on to the user. Such errors are relatively rare, so do not particularly dwell on them. It is enough to notify the user, record the event in the log and synchronize again.
Requests to the server are sent in the background strictly in turn to avoid any errors (when the request to update the data comes before the request to create a new item).
Another trick that Alex McCaw offers, following the example of
Backbone, is the generation of temporary CIDs on the client side, which are a replacement for the unique IDs generated on the server side. This approach eliminates delays and preserves an instant response for any JavaScript functions that need to generate an ID.
Backbone uses different APIs for different types of ids.
Users.getByCid(internalID) Users.get(serverID)
To get rid of such "duplicity", Spine takes a slightly different approach. Here, temporary identifiers (pseudo GUIDs) are used until a response from the server with a real ID is received, and after that Spine switches to it, but both identifiers remain accessible through a single API.
It is clear that in some cases the use of AUI is inappropriate. For example, in financial applications or Internet banking, the interface should accurately reflect the movement of funds, receiving a response from the server. But in most cases, AUI has distinct advantages over traditional Ajax application interfaces.