1

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?

guest271314
  • 1
  • 15
  • 104
  • 177
  • This Question/Answer is intended to be [canonical](https://meta.stackoverflow.com/q/291992). There have been several question where this specific pattern, that it, the omission of `return`ing a value from function call or `.then()` has been the issue, including [Run JavaScript promises in order. One after the other ends](https://stackoverflow.com/q/44422851/2801559) `promise` tag efficianodos do chime in, or not, if so inclined. – guest271314 Jun 08 '17 at 15:17
  • 2
    Possible duplicate of: [Promise returns undefined](https://stackoverflow.com/q/31315450/6188402) – Washington Guedes Jul 13 '17 at 11:01
  • @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 Jul 15 '17 at 11:04
  • Related [return Json.Stringfy result](https://stackoverflow.com/q/37085922/), [Why is my function returning undefined?](https://stackoverflow.com/q/40519579/), [Fetch API - returned variable undefined](https://stackoverflow.com/q/44475873/), [$.getJSON return/scope issue?](https://stackoverflow.com/q/43691132/), [How to return value from a Promise](https://stackoverflow.com/q/45122086/) – guest271314 Jul 16 '17 at 22:21

6 Answers6

17

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`
});
guest271314
  • 1
  • 15
  • 104
  • 177
  • 3
    @NiketPathak The bounty was only to bring attention to the Question, or particular code itself, which has appeared several times in different questions. If a description of the expected result is better described at another Answer that Question will receive bounty points. Though the inquiry itself is for posterity, and reference; no other reason. See https://stackoverflow.com/help/self-answer, https://meta.stackoverflow.com/q/291992 – guest271314 Jul 12 '17 at 14:40
11

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
})
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
5

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`
})
Anurag Singh Bisht
  • 2,683
  • 4
  • 20
  • 26
1

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

JakeBoggs
  • 274
  • 4
  • 17
1

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.

Leonard2
  • 894
  • 8
  • 21
suixin
  • 11
  • 2
1

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

return result;

to the first .then().

dhh
  • 4,289
  • 8
  • 42
  • 59
Dima
  • 11
  • 1