0

I come from a PHP background and have started using node.js. Most things I am doing okay on but there are some thing thats I am having a hard time wrapping my head around when it comes to sync vs async and scope.

Here is a pretty simple example:

app.get('/register/:invite_id?' function(req, res) {
    var agent = superagent.agent(); 
    var form = {};

    agent.post('127.0.0.1/invite/' + req.params.invite_id + '/details')
         .end(function(invite_error, invite_details) {
             form.email = invite_details.body.user.email;
             //I can console.log form.email here
         });


    // I cannot console.log form.email here.. i get undefined.
    // I need to access form.email here, so I can pre-populate my form field below...
    // Sometimes however that agent.post may take 2-3 seconds


    res.render('user/register', {
        form: form
    });

});
JaredMcAteer
  • 21,688
  • 5
  • 49
  • 65
nwkeeley
  • 1,397
  • 5
  • 18
  • 28

1 Answers1

1

You have to move your call to the render function to the line with the comment in the callback function of your post:

app.get('/register/:invite_id?' function(req, res) {
    var agent = superagent.agent(); 
    var form = {};

    agent.post('127.0.0.1/invite/' + req.params.invite_id + '/details')
         .end(function(invite_error, invite_details) {
             form.email = invite_details.body.user.email;
             res.render('user/register', {
                  form: form
             });
         });
});

That way the form variable is accessible and can be rendered to the response stream.

Generally speaking, I'd also recommend to you to make yourself familiar with the concept of closures (which are, to put it simple, functions that are passed around, either as parameters or as return values).

Note: I KNOW that a closure is something slightly different than what I wrote above, but I think that for a beginner this is much easier to grasp than the bullet-proof explanation.

For an introduction to closures, you may start at What is a 'Closure'?

Community
  • 1
  • 1
Golo Roden
  • 140,679
  • 96
  • 298
  • 425
  • What would happen if I had several different agent calls I had to make to different API's would I have to nest them all within each other and then have the res.render() in the very last call? – nwkeeley Jan 03 '13 at 15:05
  • Yes. Or you might use a library that does synchronizes your calls for you, such as [async.js](https://github.com/caolan/async). But basically, yes. – Golo Roden Jan 03 '13 at 15:07
  • Okay that helps. Now in regards to scope is there any way to access a variable defined in that agent.post or is it scoped only to that agent call.... I guess with PHP I could return $x from a function is there something like that here? – nwkeeley Jan 03 '13 at 15:10
  • No, as it's a function used asynchronously, you do not have control over the code that calls it here. To put it bluntly: A variable is always scoped to a function in JavaScript. Functions can also access variables from their outer scope (which is one of the ideas behind closures), but you can never access variables from a function being in the function's outer scope. Nesting function is the correct way to handle this here. – Golo Roden Jan 03 '13 at 15:13
  • By the way: This is the same issue as with your other question, http://stackoverflow.com/questions/13975641/node-js-expressjs-async-vs-sync - and both have the same solution: Familiarize yourself with closures ;-) – Golo Roden Jan 03 '13 at 15:14
  • If your question is answered could you please mark the answer appropriately? – Golo Roden Jan 03 '13 at 15:37