How to update user interface when invoking a long process in AJAX / Javascript?

I have several processes that need to be called sequentially (I use synchronous AJAX calls). I would like to display the state of a continuous process after it is completed, and then move on to the next. Here is an example of the code I wrote.

var counter = 0; function runProcess(input, output) { doWork(); doWork(); doWork(); }; function doWork() { counter++; document.getElementById('<%=this.progressMonitor.ClientID%>').innerHTML += "Running " + counter; // some lengthy calculations for (var i = 0; i < 1000000; i++) { var foo = Math.random(); } setTimeout(updateStatus, 1000); }; function updateStatus() { document.getElementById('<%=this.progressMonitor.ClientID%>').innerHTML += "Done " + counter; } 

When I run this, I get the following response:

Launch 1Running 2Running 3Done 3Done 3Done 3

I would like to get

Launch 1Done 1Running 2Done 2Running 3Done 3

If I insert an alert () statement in the updateStatus function, I get the response / execution request that I want. Does the browser create 3 threads for 3 function calls and execute them asynchronously?

How can I run this in a series? Is SetTimeout mode set correctly? Thank you for your help.

+4
source share
3 answers

It looks like you want to queue for AJAX calls. jQuery provides a good queue function, so you can make sure that a number of functions are called one after another. Mootools and other structures provide similar functionality.

Here is the code from my fiddle that shows how to do this.

 var queueElement = $("#output"); var counter = 0; function doWork(next) { queueElement.append("Starting " + counter + "<br/>"); counter++; $.ajax('/echo/json/').always(function() { queueElement.append("Ending " + counter + "<br/>"); next(); }); } queueElement.queue('workQueue', doWork); queueElement.queue('workQueue', doWork); queueElement.queue('workQueue', doWork); queueElement.dequeue('workQueue'); // start the work queue 
+2
source

One of the things you need to understand about Javascript in the browser is single-threaded. When you change the DOM, the screen does not change until your script cancels control.

Here is the actual sequence of events when you call doWork () twice:

  • doWork() call
  • doWork() adds a running message
  • queue for calling updateStatus() to execute later
  • call doWork() again
  • doWork() adds a running message
  • queue for calling updateStatus() to execute later
  • runProcess() terminates and returns control back to the browser
  • Browser updates screen with running messages
  • The first call to updateStatus() . After its completion, the screen is updated.
  • The second call to updateStatus() performed. After its completion, the screen is updated.

You can get what you want, do not bother with calling updateStatus() at all and just print the messages made from inside doWork() .

0
source

The queue works fine. Using the queue for the $ .ajax methods that need to be called sequentially works fine. If I used the parameter "async: false" without using a queue, the user interface is updated only after the completion of all long processes.

Thanks for pointing me in the right direction! Here is my last code if someone is looking for:

 function callService(url, workflowid, modelid, next) { var jData = {}; jData.workflowid = workflowid; jData.modelid = modelid; //alert(JSON.stringify(jData)); $.ajax({ url: url, type: "POST", dataType: "json", contentType: "application/json; charset=utf-8;", async: true, cache: false, data: JSON.stringify(jData), success: function (oResult) { $("#Message").append("&nbsp;&nbsp;" + oResult.Message); if (!oResult.Success) { $("#<%:this.FailureText.ClientID %>").append("&nbsp;&nbsp;" + oResult.Error); } else { next(); } }, error: function (exc) { $("#Message").append("&nbsp;&nbsp;" + exc.responseText); } }); } function runServices() { var queueElement = $("#q"); var queueStatus = $("#Message"); queueStatus.append("<br/>Starting workflows at : " + new Date() + "<br/>"); var list = $(":input:checkbox:checked"); // getting all selected checkboxes. $(list.each(function () { var workflowid = $(this).val(); queueElement.queue("WorkflowQ", function (next) { callService("/Services/Workflow.svc/rest/runworkflow", workflowid, document.getElementById('<%=this.MODELID.ClientID%>').value, next); }); })); queueElement.dequeue("WorkflowQ"); }; <input type="button" id="ExecuteButton" value="Execute Workflow" class="button" onclick="runServices();"/> <div id="Message"></div> <div id="q"></div> 
0
source

Source: https://habr.com/ru/post/1445139/


All Articles