1
votes

Given

function doStuff(n /* `n` is expected to be a positive number */) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve(n * 10)
    }, Math.floor(Math.random() * 1000))
  })
  .then(function(result) {
    if (result > 100) {
      console.log(result + " is greater than 100")
    } else {
      console.log(result + " is not greater than 100");
    }
  })
}

doStuff(9)
.then(function(data) {
  console.log(data) // `undefined`,  why?
})

Why is data undefined at .then() chained to doStuff() call?

6
This Question/Answer is intended to be canonical. There have been several question where this specific pattern, that it, the omission of returning a value from function call or .then() has been the issue, including Run JavaScript promises in order. One after the other ends promise tag efficianodos do chime in, or not, if so inclined.guest271314
Possible duplicate of: Promise returns undefinedWashington Guedes
@washington guedes this is a canonical answer. Only flag as duplicate if you find a real good one. ( not sth like try this )Jonas Wilms

6 Answers

14
votes

Because no Promise or other value is returned from .then() chained to Promise constructor.

Note that .then() returns a new Promise object.

The solution is to return a value or other function call which returns a value or Promise from .then().

function doStuff(n /* `n` is expected to be a positive number */) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve(n * 10)
    }, Math.floor(Math.random() * 1000))
  })
  .then(function(result) {
    if (result > 100) {
      console.log(result + " is greater than 100")
    } else {
      console.log(result + " is not greater than 100");
    }
    // `return` `result` or other value here
    // to avoid `undefined` at chained `.then()`
    return result
  })
}

doStuff(9)
.then(function(data) {
  console.log("data is: " + data) // `data` is not `undefined`
});
6
votes

The problem were facing:

return 
(new Promise(..)) //the promise we want to return
.then(()=>undefined) // the promise were actually returning, which resolves to undefined

As you may already noticed, then returns a new promise. This has a good reason, it makes promise chaining easy, e.g:

getUser()//an asynchronous action
 .then(user=>login(user))//then if we get the user,promise to log in
 .then(token=>console.log("logged in,token is "+token) //then if we logged in, log it
 .catch(error=>"login failed");//catch all errors from above

But this also creates the small trap, we are facing. The solution could be returning the original promise and not the new promise automatically returned by .then() as this is resolved to undefined as the function inside then is not explicitly returning something:

//what were doing:
Promise.resolve(n*10)//the original promise resolves to n*10
.then(a=>undefined)//the then gets n*10 passed as a, but returns undefined
.then(b=>console.log(b));//b will be undefined  :0 

//what we want:
var promise=Promise.resolve(n*10);
promise.then(a=>undefined);//a is n*10, this resolves to undefined
promise.then(b=>console.log(b));//but this still logs n*10, as its the original promise  :) 

So as you can see, to return the original promise, we simply store it in a variable, then assign a .then handler to it, and have still a reference to the original promise which we can assign other handlers to ( or return ).

In action:

function doStuff(n /* `n` is expected to be a number */) {

    //create a new promise and store it

    var promise=new Promise(function(resolve, reject) {
        setTimeout(function() {
           resolve(n * 10)
        },1000);
    });

    //add a then handler to this promise  

    promise.then(result=>console.log(result + " is "+result<100?"not":""+" greater than 100"));

    //return the original one

    return promise;

}

doStuff(9).then(function(data) {
  console.log(data) //not undefined, as original promise
})
4
votes

The doStuff is returning the Promise. But, your last then function is not returning any values, hence data is coming as undefined.

In promises, value of arguments of the next then function is the returned value of the previous then function.

function doStuff(n /* `n` is expected to be a positive number */) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve(n * 10)
    }, Math.floor(Math.random() * 1000))
  })
  .then(function(result) {
    if (result > 100) {
      console.log(result + " is greater than 100")
    } else {
      console.log(result + " is not greater than 100");
    }
    return result;
  })
}

doStuff(9)
.then(function(data) {
  console.log(data) // `90`
})
1
votes

You are not returning the result from the .then() chained to the Promise. You need to add return result; to the .then()

1
votes

Because your data value is the return value of the last .then(), your last .then() doesn't have a valid return value.

So, you can add the return value in the last .then() function.

1
votes

You must return the result from the .then() chained to the Promise. In your case just add

return result;

to the first .then().