The Disturbed Buddha

Simple Observations of a Self-proclaimed Novice

Handling Multiple Asynchronous Postbacks

Sometimes multiple asynchronous postbacks get triggered. Now, I’m not talking about situations where we want to disable a submit button, so that the user doesn’t click it fifty times waiting for something to happen. Instead, I’m referring to situations where we do want each postback to happen in the order it was fired.

However, when a page makes multiple asynchronous postbacks at the same time, the default action is that the PageRequestManager gives the most recent postback precedence. This cancels any prior asynchronous postback requests that have not yet been processed. (Get further explanation.)

So, let’s create a way to “queue up” our asynchronous postback requests and fire them off in order, one by one. First, let’s create an aspx page with three buttons inside of an UpdatePanel:

<asp:ScriptManager ID="ScriptManager1" runat="server" /> 
<asp:UpdatePanel ID="UpdatePanel1" runat="server"> 
    <ContentTemplate> 
        <asp:Button ID="Button1" runat="server" Text="Button" /> 
        <asp:Button ID="Button2" runat="server" Text="Button" /> 
        <asp:Button ID="Button3" runat="server" Text="Button" /> 
    </ContentTemplate> 
</asp:UpdatePanel>

There is no need to wire up any click events in the code-behind for our sample. While you could, all that we are concerned about is that they each cause a postback.

Next, let’s add some deliberate latency into the code so that our postback requests can pile up. Every postback to the server will now take 3 ½ seconds, so that is the fastest each request can be processed.

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 
  System.Threading.Thread.Sleep(3500) 
End Sub

Now, let’s look at the JavaScript code that will manage the backed-up postback requests for us. Add this script block after the ScriptManager on the page but before the closing </html> tag.

<script type="text/javascript"> 
    var prm = Sys.WebForms.PageRequestManager.getInstance(); 
    prm.add_initializeRequest(InitializeRequestHandler); 
    prm.add_endRequest(EndRequestHandler);        

    var pbQueue = new Array(); 
    var argsQueue = new Array();       

    function InitializeRequestHandler(sender, args) { 
        if (prm.get_isInAsyncPostBack()) { 
            args.set_cancel(true); 
            pbQueue.push(args.get_postBackElement().id); 
            argsQueue.push(document.forms[0].__EVENTARGUMENT.value); 
        } 
    }       

    function EndRequestHandler(sender, args) { 
        if (pbQueue.length > 0) { 
            __doPostBack(pbQueue.shift(), argsQueue.shift()); 
        } 
    } 
</script>

The Code in Detail

First, we use the PageRequestManager to set up handlers for the beginning and end of each asynchronous request:

var prm = Sys.WebForms.PageRequestManager.getInstance(); 
prm.add_initializeRequest(InitializeRequestHandler); 
prm.add_endRequest(EndRequestHandler);

Queuing up the Postbacks…

Then we create an array to store the originator of each asynchronous postback that cannot be processed immediately, as well as an array to store any event arguments associated with the postback:

var pbQueue = new Array(); 
var argsQueue = new Array();

Then, at the beginning of each asynchronous postback, we check to see if the page is already in an asynchronous postback:

function InitializeRequestHandler(sender, args) { 
    if (prm.get_isInAsyncPostBack()) {...}

If it is, we cancel the new postback request, and instead, add the event target and arguments to our arrays:

args.set_cancel(true); 
pbQueue.push(args.get_postBackElement().id); 
argsQue.push(document.forms[0].__EVENTARGUMENT.value);

…and Executing Them

After each asynchronous postback completes, we check to see if there are any more queued up, and if so, we do a __doPostBack(). pbQueue.shift() pulls the first item out of the array and removes it.

function EndRequestHandler(sender, args) { 
    if (pbQueue.length > 0) { 
        __doPostBack(pbQueue.shift(), argsQueue.shift()); 
    } 
}

And that’s it. Run the page, and randomly click some buttons! If you watch the browser’s status bar, you’ll see the asynchronous postbacks piling up. Then, every 3 ½ seconds, you’ll see one of them being processed! (Remember, the 3 ½ seconds is just an arbitrary time that we added into this demonstration, and it has nothing to do with how the code really works.)

Note: If for some reason, you wanted to execute the asynchronous postbacks in reverse chronological order (i.e., the most recent requests get processed first), just replace the array.shift() command in the EndRequestHandler() with array.pop().

Advertisements

December 12, 2007 Posted by | Ajax, ASP.NET, Javascript, Web Development | 10 Comments