What is the best way to refresh the user interface while executing a lengthy operation in AJAX/Javascript?

With a need to call multiple processes in series using synchronous AJAX calls, I aim to display the status of each long-running process upon completion before proceeding to the next. Below is an excerpt from the code that illustrates this concept:


var counter = 0;
function runProcess(input, output) {
    doWork();
    doWork();
    doWork();
};
function doWork() {
    counter++;
    document.getElementById('<%=this.progressMonitor.ClientID%>').innerHTML += "Running " + counter;

    // performing 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;
}

Upon running this code snippet, the output received consist of repeated 'Running' and 'Done' logs as follows:

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

The desired outcome is closer to:

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

Including an alert() statement within the updateStatus function seems to achieve the desired execution order. Could it be that the browser initiates separate threads for each function call and executes them asynchronously?

To ensure the processes run sequentially, could there be an issue with how setTimeout is implemented? Your insights on this matter would be greatly appreciated.

Answer №1

If you're looking to manage a series of AJAX calls in a queue, there are options available in various JavaScript libraries like jQuery and Mootools. These frameworks offer functions that allow you to ensure that functions are executed one after the other.

Take a look at this example from my code snippet below:

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

Answer №2

Understanding Javascript in the browser means grasping its single-threaded nature. When modifications are made to the DOM, the screen does not update until control is released by your script.

Consider the actual sequence of events when invoking doWork() twice:

  1. Invoke doWork()
  2. doWork() adds a running message
  3. Schedule a call to updateStatus() for later execution
  4. Invoke doWork() again
  5. doWork() adds another running message
  6. Schedule another call to updateStatus() for later execution
  7. runProcess() exits, returning control to the browser
  8. The browser updates the screen with the running messages
  9. The first updateStatus() call is initiated. Once completed, the screen updates
  10. The second updateStatus() call is triggered. After completion, the screen updates again

To achieve desired results, refrain from interfering with the updateStatus() call and instead print done messages within doWork().

Answer №3

The implementation of a queue has significantly improved the functionality of my code. By using the queue in conjunction with $.ajax methods that need to be executed sequentially, I have successfully avoided UI refresh issues caused by the "async: false" option when used without a queue.

I want to express my gratitude for guiding me in the right direction! For those who may benefit from it, here is the finalized version of my code:

function callService(url, workflowid, modelid, next) {
        var jData = {};
        jData.workflowid = workflowid;
        jData.modelid = modelid;
        
        $.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"); 
        $(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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Feeling lost when it comes to tackling the Data Access Object/Layer in an Express/MongoDB setup?

I currently have an Express application that is integrated with MongoDB. My goal is to decouple my database access from the server layer. However, in trying to achieve this, I've encountered two main approaches: Passing Res as an argument //server.j ...

Is the && operator being utilized as a conditional statement?

While following a tutorial, I came across this code snippet that uses the 'and' operator in an unusual way. Is this related to React? Can someone provide an explanation or share documentation that clarifies it? {basket?.length > 0 && ...

A guide on extracting/filtering information from JSON files using JavaScript

Is it possible to extract specific data from a JSON file using JavaScript? I have imported a JSON file into my local JavaScript and I am having difficulty in retrieving and displaying certain information. Could someone offer assistance with this? The JS ...

Angular is throwing a RangeError due to exceeding the maximum call stack size

Encountering a stackOverflow error in my Angular app. (see updates at the end) The main issue lies within my component structure, which consists of two components: the equipment component with equipment information and the socket component displaying conn ...

Tips for executing embedded scripts within templates

I am using a controller to display the Instagram embedded code <div class="instagram_here" [innerHtml]="instagram_embeded_code"></div> However, it is only showing a blank Instagram block. https://i.stack.imgur.com/gNPDL.png I suspect there m ...

Error: The 'then' method cannot be invoked on an undefined object in the Parse.File.save function

I am currently utilizing the Javascript API for parse.com within an Angular JS application. My goal is to successfully save or update the user's profile picture. Below is the code snippet that I have been working with: Some HTML . . . <input type ...

Update Material-ui to include an inclusive Datepicker widget

I have integrated the Material-ui Datepicker into my website to allow users to download timed event information from a database. The issue I am facing is that when users select two bracketing dates, events for the end date are not showing up correctly. F ...

Distinct elements within a JavaScript hash

Is there a jQuery method to add a hash into an array only if it is not already present? var someArray = [ {field_1 : "someValue_1", field_2 : "someValue_2"}, {field_1 : "someValue_3", field_2 : "someValue_4"}, {field_1 : "someValue ...

Is the parsing of JSON data from AJAX requests vulnerable to a man-in-the-middle attack when using eval

After writing some AJAX code, I noticed that the server returns JSON data that I created myself and is therefore secure. In this case, it seems that using eval is perfectly fine. However, I am concerned about the possibility of a man-in-the-middle attack w ...

Obtain the corresponding element from the selectors utilized in the jquery.is function

$("#see1, #seeAlso1, .see").is(':checked') This code snippet will give you a boolean result. Are you looking for a way to retrieve the first element that matches and returns 'true'? ...

Rename multiple files in bulk

With 10000 files consisting of php, html, css, and png formats that are interconnected to operate the website's engine, I am looking for a way to perform bulk renaming in order to ensure proper functionality. Not only do I need to rename the actual fi ...

Incorporating an ASP.Net button through backend coding

I have a sleek form with an AJAX Accordion pane. I am using a Master page, but the ASPX child page is structured like this: <asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server"> <link rel="stylesheet" href="Content/theme ...

Whenever text is present, the sides of my box model, constructed using HTML5 and CSS3, are always pushed downward

When I add extra text to the body of my homepage, it causes a distortion and pushes down the sidebar and advertising boxes on the side. I'm working on this project for class and even though I've asked my teacher for help, she says the code is fin ...

Mastering JSON looping for each distinct group

I'm new to JavaScript and recently encountered an issue with JSON. Here is the object I am working with: var users = [ { "firstName":"John" , "lastName":"Doe" }, { "firstName":"Anna" , "lastName":"Smith" }, { "firstName":"Peter" , "lastName": ...

How to select the final td element in every row using JQuery or JavaScript, excluding those with a specific class

I am looking for a solution with my HTML table structure: <table> <tbody> <tr> <td>1</td> <td>2</td> <td class="treegrid-hide-column">3</td> < ...

What is the best way to filter out empty arrays when executing a multiple get request in MongoDB containing a mix of strings and numbers?

I am currently working on a solution that involves the following code: export const ProductsByFilter = async (req, res) => { const {a, b, c} = req.query let query = {} if (a) { query.a = a; } if (b) { query.b = b; } if (c) { ...

Obtaining an Array through a direct input on the command line

I am having trouble incorporating raw command line arguments in my Node.js application. When I try with simple variables, everything works as expected (node example.js variable) However, when I pass an array as an argument, it does not work properly (n ...

Is it possible to prevent a webpage from being refreshed?

I need help with an HTML page that puts the worker on pause time which will be subtracted from his/her day job. The issue is that when he/she refreshes the page, the timer starts from the beginning automatically. I want it to continue without resetting. Is ...

I'm having trouble getting the function inside onLoad to run in my Next.js project - can anyone help

While I was exploring nextjs.org and following the tutorial, I encountered an issue where the function inside onLoad wasn't executing. It's puzzling because there was no call made to that link in the networks tab of my browser's developer to ...

Guide: Generating a DIV Element with DOM Instead of Using jQuery

Generate dynamic and user-defined positioning requires input parameters: offsetHeight, offsetLeft, offsetParent, offsetTop, offsetWidth ...