Ways to monitor and manage the most recent asynchronous request

My AngularJS controller is handling asynchronous calls to a service that returns promises.

$myService.getData(ctrl.state)
.then(function(data) {
    updateInterface(data);
});

Issue arises when the promises return out of order, resulting in interface displaying incorrect data due to stale state.

I am considering a couple of solutions for this problem:

  • Keeping track of promise identifiers and only processing the latest returned promise.
  • Retaining a promise until it resolves; if a new call is made, cancelling the previous promise. The cancellation can be managed by the service.

The getData method utilizes an ajax call ($http.get), making it possible to cancel using resolve() on the _httpTimeout object. However, this approach seems overly tied to the promise's internal logic.

Is there a generally accepted best practice for addressing this asynchronous issue? Check out the JsFiddle link here.

var testDiv = document.getElementById('test');

function loadData(query, pause) {
   var data = query;

   return new Promise((resolve, reject) => {
    setTimeout(function() {
        resolve(data); 
    }, pause);
  });
}

var test = function(query, pause) {
  loadData(query, pause)
  .then(function(data) {
      console.log("got back test data", data);
      testDiv.innerHTML = data;
  });
};

test("first", 1000);
test("second", 0);
<div id="test">
</div>

Answer №1

To create a solution, one option is to connect the second call directly after the first:

function executeTask(query, delay) {
  return fetchData(query, delay)
  .then(function(data) {
      console.log("received data for task", data);
      taskDiv.innerHTML = data;
      return data;
  });
}

executeTask("initial", 1000)
  .then(function(data) {
    return executeTask("secondary", 0);
});

The .then function produces a new promise that resolves or rejects based on the outcome of the successCallback or errorCallback, respectively (unless these functions return a promise themselves, in which case the chaining process will resolve with the value from that returned promise using promise chaining).

Answer №2

This approach aims to prevent the complications that may arise from a long promise chain, especially when it exceeds a length of 15 promises.

Consider implementing the synchronization queue solution by utilizing syncArray. This queue ensures that any pending asynchronous requests are placed in order and processed based on a first come, first served basis.

If a request has not been processed from the queue, it can be pushed into the queue using the following line:

if(!isProcessFromQueue) {
    syncArray.push({query:query, pause:pause});
}

In case a request is already being processed, a delay of 1 second is introduced before attempting to process from the queue again:

if(isRunning) {
    setTimeout(function() {
    test(null, null, true);   
    }, 1000);
    return;
  }

If the queue is empty, the function will terminate at this step:

if(syncArray.length < 1) {
    return;
}

Upon completion of an asynchronous request, if the queue still contains items, another processing call from the queue is made while updating the isRunning status to false to indicate the previous request's completion:

  isRunning = false;
  if(syncArray.length > 0) {
   test(null, null, true);
  }

Below depicts the complete code snippet:

var testDiv = document.getElementById('test');

function loadData(query, pause) {
   var data = query;

   return new Promise((resolve, reject) => {
    setTimeout(function() {
        resolve(data); 
    }, pause);
  });
}
var syncArray = [];
var concatData = "";
var isRunning = false;
var test = function(query, pause, isProcessFromQueue) {
  
  if(!isProcessFromQueue) {
    syncArray.push({query:query, pause:pause});
  }
  
  if(isRunning) {
    setTimeout(function() {
    test(null, null, true);   
    }, 1000);
    return;
  }
  if(syncArray.length < 1) {
    return;
  }
  var popedItem = syncArray.shift();
  isRunning = true;
  loadData(popedItem.query, popedItem.pause)
  .then(function(data) {
      console.log("got back test data", data);
      concatData = concatData + "<br>" + data;
      testDiv.innerHTML = concatData;
      isRunning = false;
      if(syncArray.length > 0) {
       test(null, null, true);
      }
      
  });
};

test("first", 1000, false);
test("second", 0, false);
test("third", 500, false);
test("forth", 0, false);
<div id="test">
</div>

At present, cancellation of promises is not supported in the current Promise implementation. However, there are plans for its inclusion in future releases. For achieving this functionality, consider utilizing third-party library bluebird. The use of Promise.race could also be beneficial in certain scenarios.

The Promise.race setup is outlined below:

var p1 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 500, 'one'); 
});
var p2 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 100, 'two'); 
});

Promise.race([p1, p2]).then(function(value) {
  console.log(value); // "two"
  // Both resolve, but p2 is faster
});

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

Leveraging ES6 with jQuery in Symfony 4

Currently working on a simple app using Symfony 4 and trying to add custom triggers in JavaScript. Having trouble getting my additional code to work as expected, even though it's compiled by Webpack via encore. It seems like my event is not triggering ...

Waiting for a promise in Angular's ui-router before navigating to a new route

My current setup involves Angular 1.5.8 and angular-ui-router 0.3.2. Every time a route changes, I need to authenticate the user. To avoid adding the resolve property for each route individually, I decided to handle this in App.run //check permissions $ ...

Switching the URL without reloading the page in NEXT.JS

Currently, I am in the process of building an ecommerce store using NEXT.JS and Redux. Within the product listing page, I have incorporated a sorting select dropdown featuring options such as Price Low to High, Price High to Low, and New Arrivals. My goal ...

Calculating the number of attributes across various elements within an array

Can someone assist me with counting elements in a multi-object array? //constructor function function Bookdes(title, author, pages, current_page, available){ this.title = title; this.author = author; this.pages = pages; this.current_page = ...

A guide on implementing array properties in Vue 3

Currently learning the fundamentals, I have an array set up in the parent component (App.vue) data() { return { fruits: [ "apple", "pear", "cherry" ], }; }, I'm aiming to have three instances of the s ...

Preserving hyperlinks while transferring text from an HTML element using JavaScript

I'm struggling to preserve links from HTML elements while copying rich text, but have been unable to achieve it despite numerous attempts. The following code represents my best effort so far, however it only copies text without maintaining the links ...

Using AngularJS to pass objects dynamically through ng-include

Below is an example that is fully functional, except for one issue. When using node.title within the HTML code, everything works as expected. However, when trying to use {{node.title}} within the ng-include file, it does not function properly. Only the g ...

Tips for exiting a web app that is taking up your entire screen

We're currently working on making our web app run in full screen mode. We were able to achieve this by implementing these meta tags: <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar ...

Comparing object variables within Javascript's HTMLCollection

let var1, var2; // Obtaining elements from the HTMLCollection var1 = document.forms[0]; var2 = document.forms.item(0); alert(var1 === var2); // Output: "true" var1 = document.forms["myForm"]; var2 = document.forms.namedItem("myForm"); alert(var1 === v ...

Using JQuery to dynamically set dropdown option values from a JSON object

I have an HTML code snippet: $.ajax({ type: "POST", url: "hanca/hanca_crud.php", dataType: 'json', data: { id_hanca: id_hanca, type: "detail_hanca" }, //detail_hanca success: function(data) { var teks = ""; $.each( ...

Using Checkbox Filters in AngularJS

I recently came across a fascinating jsfiddle showcasing an interactive toggling filter using checkboxes: http://jsfiddle.net/ExpertSystem/wYfs4/3/ Credit goes to the talented Stack Overflow user ExpertSystem for creating this appealing jsfiddle. (Is the ...

The combination of WASM and Node.js encounters an issue when attempting to utilize 'import.meta' outside of a module

I successfully compiled the FastText C++ module to a wasm module using the provided make file, with the following flags: EMCXX = em++ EMCXXFLAGS = --bind --std=c++11 -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s "EXTRA_EXPORTED_RUNTIME_METHODS=['addOnPos ...

Utilize localstorage with Redux and Next.js to initialize the state

Having an issue when attempting to populate the initial state from local storage in order to create a store. I encountered the following error message: ReferenceError: localStorage is not defined Here is my store configuration: const store = createStore(r ...

Dealing with the complexities of recursive redirection and promises in Angular UI router

UPDATE x2 After taking your advice, I implemented numerous changes. This time, I made a sincere commitment but encountered some challenges along the way. The solution you recommended hit a roadblock at this point: // If it is, return true els ...

What is the best method for extracting HTML content from a variable using Angular.JS?

Currently, I am diving into the world of Angular.JS and working on my very first project. The task at hand involves a page filled with entries structured in the following format: <h1>Title</h1> <p>Teaser</p> <p>(a link)< ...

Create JavaScript variable from either HTML or database sources

Hello, I am trying to implement a counter that retrieves its value from a JavaScript file, but I would like to customize it. Below is the JavaScript code: function updateCounter(count) { var divisor = 100; var speed = Math.ceil(count / divisor); ...

Ways to trigger a JavaScript function upon submission of my form

I have created a code snippet to validate and submit a contact form: formValidation: function() { if ( this.formData.name && this.formData.company && this.formData.email && this.formData.industry && this.formData.phone && this.fo ...

Uploading a file with AngularJS and storing it in a database

I have been attempting to implement ngFileUpload in order to upload images and store them in a database – specifically, a mongoLab database that accepts JSON objects which can be posted using this syntax: $http.post('myMongoName/myDb/myCollection/ ...

Is there a way to switch the video source when a particular h3 tag is clicked?

https://i.sstatic.net/I2gIZ.jpgI'm currently working on building a video streaming site, but I've hit a roadblock. My challenge right now is figuring out how to make the episode selector change the video player's source. I'm a bit conf ...

Activate the HTML drop-down option upon selecting the radio button, or the other way around

I'm attempting to accomplish a task. Below is the code snippet I am working with: <form> <input type='radio' name='radio_flavour' checked/>Unique flavour<br/><input class='double-flavoured' type=&apo ...