So many times we confront this issue.
In the world of AJAX where requests take time, we’ve come to develop a handful of incredible solutions such as promises and deferred responses in order to continue to execute JavaScript with out blocking the thread. This is an incredible achievement for true async comes to existence
But what about the user? The user doesn’t give a damn about your miraculous promises. The user wants the page to do as he/she says.. NOW!
A few months ago a colleague of mine was chasing a pretty interesting bug. We were trying to figure out why some database items were getting duplicated or erased every time a user would submit a form. It made no sense for we had a bunch of form submissions that were pristine, yet some were simply corrupted.
We debugged through the AngularJS code and it was pretty straightforward. The form was getting sent to a service and that service, responded with a 200 if it was saved o,r with the corresponding error code if it was not. So what the hell was going on?
Double click was the cause of the problem. Our users were a bit older around the ages of 50-60 and they are used to double clicking everything. Hence when they submitted the form they actually submitted it twice and this cause all kinds of unhandled issues in the back end. Yes in theory there should have been a check to make sure that user has or has not submitted a form and then updated accordingly but, the UI could have been a little bit more understanding of the crowd and helped out more in handling the situation.

A simple swap from button to spinner disables the user from being able to submit twice and informs the user that the system has noted his/her request and is working on it.
Some times its trickier. For instance when we have multiple events that can take place on the same page. In this particular case, a global method that detects whether a spinner is present in the DOM or not and if so alerts the user to hold on does the trick quite effectively and elegantly.
An example of a good interaction is Ladda. Here, as the event happens, the button gets injected a spinner right there.
Another cool spinner solution for all device, resolutions and browser versions is spin.js. You should definitely give it a spin (get it?).
Some word of advice, always think about spinners early in the development cycle, and include them in every action that can potentially have latency. Your users will thank you, and you’ll avoid having to debug very weird issues.
Happy hacking!