Promise inside promise: what's the correct way to return a variable from the child promise? (JS)

JavascriptPromise

Javascript Problem Overview


I've a function like this:

function top() {
  
  //promise1
  ParentPromise({
    ...some code here...
  }).then(function() {


    //promise2
        ChildPromise({
          ..some code here...
        }).then(function(response) {
         var result = response.result.items;
         
        });
      
});

};

and i need to return result value in this way:

var myresult = start();

How i can do that? THX

Javascript Solutions


Solution 1 - Javascript

The definition of promises is that you cannot literally assign result to myresult. However, you can make myresult a promise that resolves directly to result for the caller, however many promises were used to get that. The basic idea is that inside of each function in your above block, you should be returning the next Promise in the chain. eg:

function top() {

  //promise1
  return ParentPromise({
    ...some code here...
  }).then(function() {


    //promise2
        return ChildPromise({
          ..some code here...
        }).then(function(response) {
         var result = response.result.items;
         return result;

        });

});

};

In the end, the code calling top() won't know or care that 1, 2, or 12 chained promises were used to get result. It will also be able to register an error callback in case any of those promises failed.

Solution 2 - Javascript

The neatest way in my opinion is to return the promise and chain them 'down' instead of to the left, avoiding christmas tree-like callback hell.

function top() {
  //promise1
  return ParentPromise({
    ...some code here...
  }).then(function(parent) {
    //promise2
    return ChildPromise(parent.id)
  }).then(function(response) {
    // do something with `result`
    
    return response.result.items;
  });
}

top().then(function(items){
  // all done 
});

Edit: Or in ES6 / lambda notation;

function top() {
  return ParentPromise().then(parent => {
    return ChildPromise(parent.id)
  }).then(response => {
    return response.result.items
  })
}

top().then(items => {
  // all done 
})

Edit: Or using Async/Await;

async function top() {
  const parent = await ParentPromise()
  const child = await ChildPromise(parent.id)

  return child.result.items
}

top().then(items => {
  // all done 
})

Solution 3 - Javascript

The challenge here is that you're trying to use asynchronous code in a synchronous way. You will need to change the way you think when working with asynchronous code.

One way to solve this is by having top() return ParentPromise, and then set the variable myresult using the .then() of the return of that promise.

function top() {
  ...
  return ParentPromie;
}
var myresult = ''; // default value until you have resolved your promise
top().then(result => myresult = result);

However, for this to work, you'll need to add code to resolve your promise:

var ParentPromise = new Promise(function(resolve) { 
  ... some code...
  var ChildPromise = new Promise(function(){
    ...some code...
  }).then(function(response){
    resolve(response.result.items);
  });
});

Solution 4 - Javascript

Run the following code, expanding to fit your specific circumstances. Note how it illustrates returning Promises, adding logic at various points along the way, before, during and after handling various pending logic.

function ParentPromise(){
  // add complexity here, always returning a promise(s)
  // ie Promise.all, new Promise, Promise.reject or whatever...
  // here for simplicity, just return one to resolve with a clear value
  // to see it at the other end
  return Promise.resolve({items:1234});
}
function start() {
  // any method that returns the first promise, kicking off the complexity
  return ParentPromise(/*
    infinitely complex promise-conflation (individual or Promise.all, etc)
    only requirement is that each ***return a promise***
    where each is resolved or rejected
  */)
  .then((result) => {
    // do something with `result`
    console.log(result.items);
    // note returning what we want to come out **next**
    return result;
  });

};

var myresult;

start()
.then((result)=>{ myresult = result; })
.finally(()=>{ console.log('myresult:',myresult); });

Solution 5 - Javascript

Depending on what you want

Let's say you have a model and some framework, you have something like this:

function promiseInsidePromise(req, res) {

    axios.get("example.com/api")

        .then(result => {

            // do something
            result = result + 1;

        })
        .then(result => {
            
            // call the other promise and return it into the chain
            return model.createOrder(result);

        })
        .catch(error => {

            handleError(error, req, res);

        });

}

You call the other prommise but return it's value into the main chain

 return model.createOrder();

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionValerio MarzulliView Question on Stackoverflow
Solution 1 - JavascriptKatana314View Answer on Stackoverflow
Solution 2 - JavascriptErik TerwanView Answer on Stackoverflow
Solution 3 - JavascriptRob BranderView Answer on Stackoverflow
Solution 4 - JavascriptjimmontView Answer on Stackoverflow
Solution 5 - JavascriptGoldNovaView Answer on Stackoverflow