Stop JavaScript functions from causing delayed rendering

There seems to be an issue with a visual effect not displaying in a timely manner when the call is made, rather there is a significant delay that renders it ineffective.

I am attempting to retrieve data synchronously (yes, you read that correctly, not asynchronously), display a "waiting" indicator while the retrieval is in progress, and then hide the indicator once the operation is complete. However, the problem lies in the fact that the indicator does not appear when the code responsible for it is executed; The expected visual outcome of a jQuery show() function is being delayed until after the data retrieval process. I have verified through timestamp logging in the console that the show() function indeed occurs prior to the data retrieval.

Peculiarly, the console logging itself is also visually delayed even though the timestamps indicate that the code execution happens as anticipated.

A noteworthy observation is that if an alert() call is introduced before the data retrieval, all visual processes occur immediately when the alert pops up, without waiting for the data retrieval to finish.

Below is the provided code snippet. It should be noted again that the data retrieval is done using a synchronous $.ajax() call (i.e. async: false).

fillInClient: function(clientId) {
  var result, spinner;
  console.log("spinning at " + ($.now()));
  spinner = $("tr#client_" + clientId + " .spinner");
  spinner.show();

  // If I call alert("foo") here, I see both the spinner.show() and 
  // the first console.log immediately. After a few seconds, 
  // I see the hide() and the second console.log

  // Without alert(), I never observe the show() and the first console.log
  // only appears after this:

  // This operation takes several seconds
  result = $.ajax({
    type: "GET",
    url: "/advisor/householding/accounts?user=" + clientId,
    async: false
  });  
  spinner.hide();
  console.log("stopping at " + ($.now()));
  return result;
}

The console output shows simultaneous appearances, but the timestamps clearly indicate a time difference of several seconds between them.

spinning at 1418933857688
stopping at 1418933862374

Your assistance on this matter would be greatly appreciated...

Answer №1

When the browser attempts to repaint every n milliseconds, it will wait until the call stack is empty before rendering if it's blocked at that point in time. In your scenario, you're displaying a spinner, making a synchronous ajax request, and then hiding the spinner. This causes the callstack to never empty between showing and hiding the spinner, preventing the browser from repainting and resulting in the spinner being hidden before it can be rendered.

To fix this issue, you need to move the blocking code off the stack so that the browser can render before getting blocked. One approach is using setTimeout, but this method drastically alters the behavior of your code to almost mimic an asynchronous request. Here's your code with a synchronous request utilizing setTimeout:

fillInClient: function(clientId, doneCallback) {
  var result, spinner;
  console.log("spinning at " + ($.now()));
  spinner = $("tr#client_" + clientId + " .spinner");
  spinner.show();

  setTimeout(function () {
    var result = $.ajax({
      type: "GET",
      url: "/advisor/householding/accounts?user=" + clientId,
      async: false
    });
    doneCallback && doneCallback(result);
    spinner.hide();
    console.log("stopping at " + ($.now()));
  }, 20);
  //return result;
}

The updated function no longer returns the result directly and instead relies on a callback function. At this point, it may be more efficient to switch to an asynchronous request and eliminate the use of setTimeout.

fillInClient: function(clientId, doneCallback) {
  var result, spinner;
  console.log("spinning at " + ($.now()));
  spinner = $("tr#client_" + clientId + " .spinner");
  spinner.show();

  $.ajax({
    type: "GET",
    url: "/advisor/householding/accounts?user=" + clientId
  })
  .done(doneCallback)
  .always(function () {
    spinner.hide();
    console.log("stopping at " + ($.now()));
  });
}

Answer №2

If you're looking for a way to make your asynchronous code feel synchronous without using AJAX, I recommend utilizing callbacks. Here is an example:

fillInClient: function(clientId) {
    var result, spinner;
    console.log("spinning at " + ($.now()));
    spinner = $("tr#client_" + clientId + " .spinner");
    spinner.show();
    result = $.ajax({
        type: "GET",
        url: "/advisor/householding/accounts?user=" + clientId,
        complete: function (){
            spinner.hide();
            console.log("stopping at " + ($.now()));

            //Other logic to run after the call completes
        }
    });
}

Instead of trying to force a synchronous request with AJAX, let the complete() function handle any tasks that need to happen after the AJAX call finishes. This ensures a smooth flow of execution in your code.

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

One way to include query parameters before initiating navigation in Angular

Imagine having two components called A and B. When Component A navigates to /a?random=random and B navigates to /b, I need to include the authUser query parameter before the navigation begins. This way, the final URLs should look like this: /a?random=rando ...

Deleting a file in Express.js after it has been downloaded from the local file system

I'm working on an Express handler that is designed to download a file after detecting a valid file path in the directory entries. The handler includes a command-line option to delete the file after it has been successfully downloaded: res.downloa ...

Use ng-class in a P tag to assess a variety of expressions

Is there a way to apply ng-class to automatically evaluate negative values within a < p > tag? <p <strong>LW$:</strong> {{d.lw_metric}} <strong>LW:</strong> {{d.lw_metric_percentage}} <strong>L4W:</strong> {{ ...

What is the best method for properly inserting images into a Vue Carousel 3D slider?

I'm currently exploring the Vue Carousel 3D documentation and I am having trouble displaying a single image on each slide. Let me elaborate: I aim to create a slider similar to the one shown in the Controls Customized example in the documentation. Th ...

multiple server-side tables with toggle buttons

I'm struggling with a page that contains 3 tables using datatables. The issue is that datatables can't handle more than one table, and after searching for a solution, I found a customized SSP Datatables at this link: here However, I'm wonde ...

Is there a way to show information exclusively on the selected card upon clicking?

[click here to see image 1] https://i.sstatic.net/cfvUT.png [click here to see image 2] https://i.sstatic.net/ISXAU.png Greetings, fellow beginners! Once again I find myself stuck on a coding problem. I have fetched various workout data and displayed t ...

The problematic $index issue in Angular with Internet Explorer 8

I created a repeating element that stacks multiple items on top of each other. While this functionality works as expected in modern browsers, it encounters issues in IE8 where the style attribute is not parsed correctly (potentially due to invalid content ...

Running code concurrently in JavaScript

Currently, I am in the process of learning Angular.js and decided to create my own authentication code using a REST-like API. Below you can find the implementation of my authentication service. The main issue with my signIn function is that it consistentl ...

Having an issue with retrieving value from a textfield in JavaScript

<input id="checkOldPassword" type="button" title="Check New Password" value="Check New Password" onclick="checkPassword()" /> <input id="newPassword" type="text" maxlength="8" min="8" /> <script language="javascript"> function checkPassw ...

How can I troubleshoot Ajax not loading my additional external JavaScript files?

$(document).ready(function () { $("#livesearch").on("keyup",function(){ var search_term = $(this).val(); $.ajax({ url:"ajax-live-search.php", type:"POST", d ...

Helping React and MUI components become mobile responsive - Seeking guidance to make it happen

My React component uses Material-UI (MUI) and I'm working on making it mobile responsive. Here's how it looks currently: https://i.sstatic.net/kxsSD.png But this is the look I want to achieve: https://i.sstatic.net/kJC2m.png Below is the code ...

Disabling the default behavior using preventDefault does not have an effect on ajax requests

I'm having an issue with my preventDefault event not working and I can't figure out why. I've searched around but haven't been able to pinpoint the problem. If there's a solution out there, please forgive me! Here's the code I ...

steps for setting up babel-cli and babel-preset-react

I attempted various methods of installing babel-cli babel-preset-react Here's what I tried: npm install --save-dev babel-cli babel-preset-react However, when I run babel -h An error message appears saying The program 'babel' can be found ...

"Execution of the console.log statement occurs following the completion of the request handling

When I have a piece of middleware that responds if no token is found, why does the console.log line still run after the request is responded to? I always believed that the res.json call would "end" the middleware. Any insights on this behavior would be g ...

What methods can be used to ensure a required minimum delay time between function executions?

For my node function, I am aiming for a specific execution delay of around 5 seconds. The minimum delay needs to be implemented within the function itself, not externally, so external users are unaware of the delay. Therefore, I cannot rely on modules l ...

I am looking to continuously update a div element on my website with data sourced from another site. My goal is to enable the div element to refresh automatically without

I am looking to continuously update the getPrice($url) function every 1 second without the need for manual page refresh. <?php ini_set('display_errors', '1'); Currently, the getPrice($url) function only refreshes when I manual ...

Implementing a queue with an on-click event

As a self-proclaimed Java nerd diving into the world of jQuery, I'm facing some challenges. My goal is to create 3 interactive boxes that behave in a specific way: when clicked, one box should come forward while the other two dim and stay in the back ...

Prevent the cursor from moving when the focus changes in Vuetify

I created a code pen that allows the user to trigger the dropdown menu for the second v-autocomplete by entering text in the first v-autocomplete. I achieved this by setting isFocused to true. However, an issue arises where the cursor automatically moves t ...

Having trouble with removing the disabled attribute from an input file submit button

Currently, I am in the process of validating the file size and extension before it gets uploaded. My code is almost functioning perfectly, but there seems to be an issue with removing the disabled attribute from the submit button when the file meets all th ...

`How can I replace a link with text within a div using JavaScript or jQuery?`

I need help transforming the following HTML code: <div id="myText">Another hurricane is coming <a data-number="23">here</a>. And check out pictures <a data-number="43">here</a>.</div> into this: <div id="myText"> ...