AJAX calls have taken web work to a new level. You no longer need to reload the page in response to each user input. Now it is possible to send calls to the server and refresh the page based on the responses received. This speeds up the work of the interactive interface.
But what AJAX does not provide is the updates from the server that are necessary for the application to work in real time. These can be applications in which users simultaneously edit one document, or notifications sent to millions of news readers. Another template is needed for sending messages, in addition to AJAX requests, which would work at different scales. For this, the PubSub template (“publish and subscribe”, “publication and subscription”) is traditionally used.
What task solved AJAX
Before AJAX, interactive interactions with the page were heavyweight. Each of them required reloading the page that was created on the server. In this model, the main unit of interaction was the page. It does not matter how much information was sent from the browser to the server - the result was a fully updated page. It was a waste of both traffic and server resources. And it was slow and inconvenient for users.
')
AJAX solved the problem by breaking everything apart: it became possible to send data, get a specific result and update only the part of the page relevant to it. From the “give me a new page” call, we moved to specific data requests. We have the opportunity to make remote procedure calls (
RPC ).
Consider a simple web voting example:

Using AJAX, the processing of clicking on “Vote” is approximately as follows:
var xhr = new XMLHttpRequest(); xhr.open('get', 'send-vote-data.php'); xhr.onreadystatechange = function() { if(xhr.readyState === 4) { if(xhr.status === 200) {
Then you need to change only one vote count. From redrawing the page, we moved on to changing a single DOM element.
The server has less work and the traffic has decreased. And most importantly, the interface is updated faster, improving the attractiveness of use.
What is missing
In the real world, such an application will receive many votes in parallel. The number of votes will vary. Since the only connection between the client and the server will be AJAX requests, the user will see the results only when the application loads. Then the changes will not be transmitted to the user.
AJAX refreshes pages only in response to user actions. It does not solve the problem of processing updates coming from the server. It does not offer a way to do what we need: to transfer information from the server to the browser. This requires a messaging pattern that sends updates to the client without user intervention and without the need for the client to constantly poll the server.

PubSub: one-to-many updates
The established template for such tasks is the PubSub. The client declares his interest in a topic (subscribes) to the server. When a client sends an event to a server (publishes), the server distributes it to all connected clients.
One of the advantages is that publishers and subscribers are not connected to the server. The publisher does not need to know about the current subscribers, and subscribers - about the publishers. Therefore, PubSub is easy to implement both for those and for others, and it scales well.
Pattern implementations are many. You can use
Faye on Node.js or Ruby. If you do not want to keep your server, you can use web services like
Pusher .
Two templates for sending messages, two technologies?
It's pretty easy to find a PubSub technology that is suitable for the needs of a particular application. But even in such simple applications as voting, it is necessary to implement both RPC and PubSub — sending data, requests, and receiving updates. Using pure PubSub, you have to use two different technologies: AJAX and
This approach has disadvantages:
- organization of two different stacks, possibly two servers
- separate application connections for two templates, high server load
- on the server you need to integrate two stacks in one application and coordinate them with each other
- the same on the frontend
WAMP: RPC and PubSub
Web Application Messaging Protocol (
WAMP ) solves these problems by integrating RPC and PubSub into one protocol. One library, one connection and one API.
The protocol is open, and for it there is an open JavaScript implementation (
Autobahn | JS ), which works both in the browser and under Node.js. For other languages, there are also implementations, so you can use PHP, Java, Python, or Erlang on the server.

WAMP libraries can be used not only on the backend, but also for native clients, allowing you to combine web and clients running on the same protocol. The C ++ library is well suited for running WAMP components on devices with limited resources.
Connections do not occur from the browser to the backend, but through a WAMP router that distributes messages. For PubSub, it plays the role of a server — your server publishes a message for the router, and it already distributes it. For RPC, the frontend sends a request for a remote procedure to the router, and it forwards it to the backend, and then returns the result.
Let's see how to solve our problem with voting with the help of WAMP.
Voting update live: WebSockets and WAMP
For simplicity, our backend will also be written in JS and will work in another tab. A browser backend is possible because browser clients can register procedures for a remote call just like any other WAMP client.
The code for the demo is on
GitHub , along with instructions for launching it.
Crossbar.io is used as a router.
WAMP library connection
To get started, let's connect the Autobahn | JS library.
For demonstration purposes, you can connect it as follows:
<script src="https://autobahn.s3.amazonaws.com/autobahnjs/latest/autobahn.min.jgz"></script>;
We establish connection
var connection = new autobahn.Connection({ url: "ws://example.com/wamprouter", realm: "votesapp" });
The first argument is the URL of the router. The ws scheme is used because WAMP uses
WebSockets as the default transport. In addition, HTTP headers are not transmitted during communication, which reduces traffic. WebSockets are supported in all
modern browsers .
The second argument we set is “realm”, the space to which the connection is attached. Spaces create separate domains for routing on the server — that is, messages are transmitted only within a single space.
The created object allows you to attach two callbacks - one for a successful connection, and the second for an unsuccessful one, and for the moment when the connection is interrupted.
The onopen handler is called upon establishing the connection, and receives the session object. We pass it to the main function, which contains the functionality of the application.
connection.onopen = function (session, details) { main(session); };
Next, you need to run the opening of the connection:
connection.open();
Register and call the procedure
The frontend sends votes by calling a procedure on the backend. Define the function of processing the transmitted voice:
var submitVote = function(args) { var flavor = args[0]; votes[flavor] += 1; return votes[flavor]; };
It increases the number of votes and returns this number.
Then we register it on the WAMP router:
session.register('com.example.votedemo.vote', submitVote)
At the same time, we assign it a unique identifier used for the call. For this, WAMP uses URIs in the form of Java packages.
Now the submitVote function can be called from any authorized client from the same space. The call looks like this:
session.call('com.example.votedemo.vote',[flavor]).then(onVoteSubmitted)
What submitVote returns is passed to the onVoteSubmitted handler.
Autobahn | JS does this through regular callbacks, but with
promises : session.call immediately returns an object that is processed at the time the call is returned, the callback is made, and then the handler function is executed.
For simple use cases of WAMP and Autobahn | JS, ​​you don’t need to know anything about promises. You can consider them another callback entry.
Subscribe and send updates
What about updating other clients? To receive updates, the client must inform the router what information it needs. For this:
session.subscribe('com.example.votedemo.on_vote', updateVotes);
We pass on the topic and the function that will be called each time the information is received.
It remains only to configure the sending of updates from the server. Create an object to send and publish information on the topic we need. We will add this functionality to the previously registered submitVote:
var submitVote = function(args, kwargs, details) { var flavor = args[0]; votes[flavor] += 1; var res = { subject: flavor, votes: votes[flavor] }; session.publish('com.example.votedemo.on_vote', [res]); return votes[flavor]; };
That's all: sending votes to the backend and updating votes for all connected browsers work on the same protocol.
Total
WAMP unifies message passing. RPC and PubSub should be enough for all application tasks. The protocol works through WebSockets, fast, single and bidirectional connection to the server. Since the WAMP protocol is open and its implementations already exist for different languages, you are free to choose technology for use on the backend and even write applications for native clients, and not just for the web.
Notes
“
Vote ”, Crossbar.io - the current version of the vote
“
Why WAMP? ", WAMP - explanation of the development of the protocol
“
Free Your Code: Backends in the Browser ,” Alexander Gödde, Tavendo - an article on how protocol symmetry affects deployment
“
WebSockets: Why, What and Can I Use It? ”, Alexander Gödde, Tavendo - WebSockets Review
“
WAMP Compared ”, WAMP - protocol comparison with others
Crossbar.io - an introduction to using a universal router for applications