0

I'm trying to return a value from a promise, but I can't. Why it doesn't work?

I get Promise { <pending> } output only.

function

  function username() {
    return new Promise(function (resolve, reject) {
      user.where('id', req.id).fetch().then(function (data) {
        data = data.toJSON();
        resolve(data);
      });
    });
  }

variable

var r = username().then(function (a) {
    return a.username;
  });

  console.log(r);

If I remove return and put console.log(a.username), it works, but it's not the result I want. I want to put returned value inside r.

EDIT #1

I need to pass my returned values into a view (like below), so I must be able to access them outside of the then() chain.

res.render("frontend/index", {
    value1 : value1,
    value2 : value2,
    value3 : value3
  });

EDIT #2

I'm using Express.js

Now I get "Error: Can't set headers after they are sent." error, I hope it's more clear now. When a user tries to access a page, I query the database and pass variables to a view, but there are more than one operation per view (username, post info, comments, etc).

exports.index = function (req, res) {

  function username() {
    return new Promise(function (resolve, reject) {
      user.where('id', req.id).fetch().then(function (data) {
        data = data.toJSON();
        resolve(data);
      });
    });
  }

  username().then(function (b) {
    res.render('backend/index', {
      username: b.username
    });
  });

  function post() {
    return new Promise(function (resolve, reject) {
      post.where('id', req.params.postId).fetch().then(function (data) {
        data = data.toJSON();
        resolve(data);
      });
    });
  }

  post().then(function (a) {
    res.render('backend/index', {
      post: a.post
    });
  });

};
4
  • AFAK then() retuns a promise, so r is a promise, not its result. Commented Nov 22, 2015 at 4:23
  • "want to put returned value inside r" What is next process for r ? Commented Nov 22, 2015 at 4:28
  • You cannot access the values outside of the .then chain. Commented Nov 22, 2015 at 4:55
  • "so I must be able to access them outside of the then() chain." Why can res.render not be called within .then() Commented Nov 22, 2015 at 4:59

3 Answers 3

1

The .then() function returns a promise only. Here in above code variable r is nothing but a promise reference object.

If you want to use the returned response from the promise, this is how you will do it -

username().then(function (a) {

   console.log(JSON.stringify(a));
   // you will need to use the response returned from server here..
  // display in view or something else
  res.render("frontend/index", {
      value1 : a.value1,
      value2 : a.value2,
      value3 : a.value3
 });

 });

Returning a value from inside a promise thenable function will only return a promise and not the value.

You will need to wait till all the promises are resolved and then only send the response from the server. Once a response is sent, you can not send it again and hence the error headers....

Updated answer as per modified question -

 exports.index = function (req, res) {

    function username() {
        return new Promise(function (resolve, reject) {
            user.where('id', req.id).fetch().then(function (data) {
                data = data.toJSON();
                resolve(data);
            });
        });
    }

    function post() {
        return new Promise(function (resolve, reject) {
            post.where('id', req.params.postId).fetch().then(function (data) {
                data = data.toJSON();
                resolve(data);
            });
        });
    }

    username().then(function (b) {

        post().then(function (a) {

            res.render('backend/index', {
                post: a.post,
                username: b.username
            });
        });

    });
};
Sign up to request clarification or add additional context in comments.

5 Comments

You can call res.render(...) inside the then function also. Basically that should be the way.
If you want to do anything with the returned response, it should be called inside .then(function(){ // here }) only...
Thanks, but what if I'm dealing with multiple functions (username, posts, categories, etc) to serve a view? Do I need to use res.render for each function?
If different functions involve or depend on different promises then yes.
Thank you for your help, I don't know whether I should ask a new question or not, so here it goes. Could you please check edit #2 out?
1

Try performing next process where fulfilled value of r is used inside of .then() to access asynchronous returned value from Promise r

var r = username().then(function (a) {
    return a.username;
});

r.then(function(data) {
  // `data` : `r` return value
  // do stuff with `data` here
});

Comments

1

You'll have to restrict the usage of the value to functions passed to .then. There is no other logical way to assert that the value of r has been assigned.

var r;
username().then(function(a) {
  r = a.username;
  // use r here

  // resolve promise with value of username
  return r;
}).then(function(username) {
  // or use it here
});

2 Comments

the very first time variable r will log as an undefined.
Yes, console.log will be called before the function resolves, only way to force it would be to put it inside another then() call.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.