Tips for optimizing the use of JS promises?

I'm encountering issues with implementing promises in JavaScript.

There are 3 asynchronous functions that rely on each other:

The functions are named func1, func2, and func3 respectively.

  • func1 produces a single result that func2 requires.
  • func2 also generates a single result.
  • func3 relies on results from both func1 and func2.

As a consequence, func3 needs to wait for the completion of both func1 and func2, while func2 only waits for func1.

Although I managed to create a working JS fiddle, dealing with the combined usage of all three functions is quite messy. What would be the best approach to handle this chained operation effectively?

function func1() {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve(10);
    }, 1000);
  });
}

function func2(return1) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve(return1 + 20);
    }, 1000);
  });
}

function func3(val1, val2) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve(val1 + val2);
    }, 1000);
  });
}

// The function calls chaining
func1().then(function(result) {
  func2(result).then(function(result2) {
    func3(result, result2).then(function(finalResult) {
      console.log(finalResult);
    }, function(err) {
      console.log(err);
    });
  });
}).catch(function(err) {
  console.log(err);
});

Answer №1

When working with promises, there are different approaches you can take. One option is to utilize the closure scope and nest your promises, as shown below:

func1()
  .then((result) => {
    return func2(result).then((result2) => ({result, result2}));
  })
  .then(({result, result2}) => {
    return func3(result, result2);
  });

Another approach is to store results outside of the promises' scope, like this:

let result;

func1()
  .then((_result) => {
    result = _result;
    return func2(result);
  })
  .then((result2) => {
    return func3(result, result2);
  });

If your environment supports async/await functions, you could refactor it in the following way:

async function fn() {
  const result = await func1();
  const result2 = await func2(result);
  const result3 = await func3(result, result2);

  return result3;
}

fn().then((result3) => console.log(result3));

For environments that support generators, you can use the co library to create co-routines:

const fn = co.wrap(function*() {
  const result = yield func1();
  const result2 = yield func2(result);
  const result3 = yield func3(result, result2);

  return result3;
});

fn().then((result3) => console.log(result3));

Answer №2

UPDATE: After reviewing the guidelines again, I realized that the approach suggested by SimpleJ is the correct one to follow.

When a value is returned in a then callback, it becomes thennable itself. This means you can process your promises sequentially by returning the next function from the then callback of the previous one.

Instead of:

func1().then(function(result) {
  func2(result).then(function(result2) {
    func3(result, result2).then(function(finalResult) {
      console.log(finalResult);
    }, function(err) {
      console.log(err);
    });
  });
}).catch(function(err) {
  console.log(err);
});

Try this:

func1()
  .then(result => func2(result))
  .then(result => func3(result))
  .then(result => console.log('Final result', result))
  .catch(err => console.error(err))

I've changed your functions to arrow functions for clarity, but it functions the same way as yours did.

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

Preventing an iframe from reloading when transferring it to a new parent using appendChild

I'm looking to relocate an iframe to a different parent element while maintaining the iframe's current state (including scroll position and any entered form data). Unfortunately, when I use appendChild() to move the iframe, it reloads and resets ...

Hide a div when multiple classes are filtered using jQuery

I have several divs with the class .item. When the user clicks on the Classfilter submit button, all .item elements that also have at least one class from the dateClasses array (for example ['28.09.2015', '29.09.2015']) should be hidden ...

Obtaining information from the HttpServletResponse through an AJAX form

In my "first.jsp", there is a form containing hidden input values and pointing to another jsp file. <form id="popupForm" name="popupForm" action="<%= cqRequest.externalizeHref(handle) %>" method="post"> <input type= ...

Updating the KML data on Google Maps V3 for a fresh look

I recently updated a map from V2 to V3 and I am working on incorporating code to automatically refresh the KML data every 30 seconds. The goal is to update the map with the latest data and display a countdown until the next refresh. Here is an example of ...

How can I trigger the execution of textarea HTML code with an onClick event using JavaScript?

When my fingers are lifted from the keyboard, some code will be automatically executed. I want to trigger this function when I click a button (onclick) instead of using onkeyup. <div id="result"></div> <textarea ...

Filtering database records using a static dropdown list in MVC 5: A step-by-step guide

Is there a way to filter database records based on the columns QtyRecieved, QtyRecievedand Void using a static HTML dropdown list? The QtyRecieved and QtyRecievedand column are both decimal values, while Void is a boolean. This is what I have attempted: ...

Pass for Achieving the Bokeh2 Effect

I'm attempting to transfer the Bokeh2 Depth of Field effect to an effect composer pass. Every time I try to run it, I encounter the following error: glDrawElements: Source and destination textures of the draw are the same. Below is the render functi ...

SignalR enables the display of identical dashboard data pulled from queries on various browsers. By utilizing SignalR/hub, MVC, and C#.NET, the data can

Encountering an issue with my signalr/hub while fetching dashboard data. I'm using 2 browsers to access data based on dates. However, when searching for July on browser 1 and then switching to another month on browser 2, the data in browser 1 gets upd ...

Utilizing Google's GeoApi to retrieve users' location data regarding their city and country

I am currently using this code to retrieve the full address information of users function getGeo() { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(function (a) { $("#geoLoc").html("Determining your location. ...

Exploring and verifying data within an array in ReactJS

In ReactJS, there is a variable that contains the result of validation as an array: console.log(this.state.check); // [account: false, name: true, email: true] Here's what needs to be done: If all values in the array are true, return true. If one or ...

Vue 2 draggable does not maintain reactivity when the v-model value consists of a parent tag's iterable

Utilizing Vue 2 alongside Vuex, the incoming object gets organized into distinct sub-objects according to the classCategory value. Could it be failing because the v-model value in draggable is a key sourced from the parent tag object? <div class="c ...

The parameter of type 'never' cannot be assigned with the argument of type 'number | boolean | undefined'

In my project, I am creating a validation input using TypeScript in Next.js. interface InputRules { required?: boolean min?: number max?: number minLength?: number maxLength?: number } I have defined an object that contains methods to handle val ...

Instead of using a string in the createTextNode() function, consider utilizing a variable

I am attempting to use JavaScript to add another list item to an unordered list. I want the list item to display dynamic content based on a pre-existing variable. While I can successfully append a list item by using a string, things go awry when I try to i ...

What advantages does the Step function (AWS) offer compared to setTimeout (Javascript) for scheduling tasks?

I am currently in the process of developing an API service that allows any client to provide me with their HTTP request along with the desired time in seconds for execution. I have considered two potential approaches to achieve this: Utilizing a lambda f ...

How to stop a checkbox from being selected in Angular 2

I have a table with checkboxes in each row. The table header contains a Check All checkbox that can toggle all the checkboxes in the table rows. I want to implement a feature where, if the number of checkboxes exceeds a certain limit, an error message is ...

Get the host name using Node.js server without using the 'req' parameter

Currently, I am utilizing req.headers.host to identify the host name of the server, which works well when dealing with incoming requests at the server. However, I am curious about how one can determine the host name without a request (i.e. without req). T ...

JavaScript - Two tables shown in parallel

Beginner coder seeking assistance! I am currently working on an application with two user input fields placed adjacent to each other. Clicking parse buttons next to these fields generates two separate tables. However, I need these tables to be displayed si ...

issue with AngularJS model not initially binding to select dropdown

I am facing an issue with a select dropdown in my code. I am using ng-repeat to populate the dropdown like this: <select ng-model="tstCtrl.model.value" required> <option ng-repeat="option in tstCtrl.myOptions" value="{{option.a}}">{{option.b ...

"Create a smooth transition effect in CSS by fading out one div and fading in

I've set up a grid of buttons, and my goal is to have the grid fade out when a button is clicked, then fade in with a new div in its place. This involves animating opacity from 1 to 0 and vice versa while toggling the display:none property for content ...

Issues with the navigator.contacts.find function occurring when using cordova or phonegap

I am attempting to retrieve the contacts stored on a mobile device. The code snippet I am using is not functioning as expected - specifically, the navigator.contacts.find method isn't producing any outcomes. There are no error messages or success conf ...