

AJAX best practices? - morris

I'm new to the AJAX business and am trying to find a resource outlining the basics.  In particular, I'm very concerned with handling out of order asynchronous requests, but can't seem to find a very solid recommendation on how to handle them.  As of now I'm going to implement a queuing system for dynamic requests but would rather not re-invent the wheel...  
======
jey
What's the specific problem? Why do you need the results to be ordered? If you
really do need to order the results, just attach a sequential ID to each
request, then hold a priority queue of results sorted by request ID. Pseudo-
code follows:

    
    
      next_request_id = 0;
      next_response_id = 0;
    
      // the following code assumes there's a PriorityQueue class implementing a
      // priority queue with push(object, priority) and pop() operations
      response_queue = new PriorityQueue();
    
      function send_request(request) {
          request.request_id = next_request_id;
          next_request_id++;
          ajax_send(request);
      }
    
      function receive_response(response) {
          response_queue.push(response, response.request_id);
    
          while(!response_queue.empty()
                  && response_queue.top().request_id == next_response_id) {
              handle_response(response_queue.pop());
              next_response_id++;
          }
      }
    

The above code isn't very robust as it doesn't deal with requests that die in
transit and never return a response, etc.

~~~
morris
Right - this is what I'm about to try to implement (and I think I'd trash the
entire queue if a response isn't returned within some timeout limit and
display a subsequent error message). I don't know if this is the best practice
though and as this seems like a pretty generic AJAX problem, it feels like
there should be a pretty generic solution...

~~~
jey
I doubt most AJAX applications are that reliant on request/response ordering.
However, a priority queue _is_ the generic solution. :-)

------
palish
One way to handle it is to design your system so that it doesn't matter if the
requests come back out of order. Could you give an example of where order
matters, so we can work on designing it so that order doesn't matter?

~~~
morris
I'd like to implement a note-taking system, with an auto-save feature (say,
set by a timer). If the requests that go out to the server are received out of
order, the wrong state will be auto-saved.

~~~
palish
Don't save again until the first save has been registered. If it times out,
try again.

~~~
morris
Right - so this would amount to creating queue? Nevermind, I see what you're
saying... This is a very specific instance of something pretty general though.
Lets say the user edits a note and then deletes it. Do I have the delete
action wait for any saves that went out complete first? As the system gets
more and more complex it would be something of a pain to try to work out
dependencies every time I want to add a new feature.

~~~
jey
Yes, queue up the deltas, then only send the full set of deltas every time the
timer fires. This will also prevent you from hammering your server with a
stream of requests backing up.

~~~
morris
Now, lets say I want to stay away from auto-save... The app I'm working on
will actually be a widget on the side of the main site and so I'm not
confident the user will pay enough attention to know if his/her info has been
saved before they navigate to another page. In this case, can I still avoid a
queue? I'd want every action a user takes (adding a note, editing it, deleting
it) to result in a server request and some spinny wheel notification that the
request is being processed. By the way, thank you both for your help!

~~~
palish
You don't need a queue.. Just issue the commands as the user makes them. Each
command should be separate from every other command, so that order doesn't
matter.

~~~
morris
I think order does matter - lets say a user types in 'hello' and then saves
the note, then quickly changes his/her mind and types in 'hello world' and
saves the note. Now the backend will save the version of the note which it
receives last, which could be 'hello' depending on network lag.

~~~
palish
In that instance, you'd abort the previous request, create a new
XmlHTTPRequest object (important step), then re-issue the request.

~~~
morris
How does one abort the previous request unless a queue is being kept track of?
Also, there could have been a few other requests made between the first save
and the second save. Its definitely possible I'm just not understanding how
XMLHTTPRequest objects work - please do explain if you think that is the case.

Also - I'm not necessarily using XMLHTTPRequest, I'm leaning towards dynamic
scripting as my site will need this widget to run across several different
subdomains - dynamic scripting doesn't have a lot of the nice status
functionality that XMLHTTPRequest does...

~~~
palish
Okay, here's an alternate method.

    
    
     When a user needs to save their note
      If the note is already saving
       Set note.saveAgain = true
      else
       Start the process of saving the note
     
     When the note has saved
      If note.saveAgain == true
       Set note.saveAgain = false
       Start the process of saving the note again
    

That doesn't require a queue. It also only saves the most up to date version.

~~~
morris
Cool.

Thanks again.

~~~
palish
I can has karma now?

 _Edit:_ How dare I ask to be compensated for my time. I should be ashamed of
myself.

~~~
palish
Thanks!

If you have any more questions, feel free to ask.

