10

I want to write an application that requests a token from an API. As long as this token isn't available I don't want to continue with the rest of the application. So it has to be like a synchronous HTTP request.

My goal is to create a function that does the request and then returns the token like:

var token=getToken();  //After this function has finished
makeRequest(token);   //I want this function to be executed

How can I do this?

Apatus
  • 143
  • 1
  • 2
  • 10

4 Answers4

16

It doesn't want to be synchronous at all. Embrace the power of callbacks:

function getToken(callback) {
    //get the token here
    callback(token);
};

getToken(function(token){
    makeRequest(token);
});

That ensures makeRequest isn't executed until after getToken is completed.

Taintedmedialtd
  • 856
  • 5
  • 13
  • 1
    So this means that in the callback function my whole code has to be executed? – Apatus Mar 09 '17 at 17:16
  • @Chaos_: Yes, as is always the case with asynchronous code (syntactic sugar like `await` notwithstanding). – T.J. Crowder Mar 09 '17 at 17:19
  • If you want. It helps to modularise functions that perform different tasks because you'll probably use them again and you shouldn't repeat yourself. If you've used other synchronous languages before like PHP the new style of syntax might take some getting used to. Just remember in your first example var token is undefined until getToken() is completed and makeRequest will execute straight away, with or without (most likely without) getToken completing. – Taintedmedialtd Mar 09 '17 at 17:22
  • You have no idea how awesome this answer is. All the other explanations on the web are so grandiose and confusing. this is as simple as it gets, and tremendously helpful. If I could up-vote this twice, I would. Thank you! – heyitsalec Jun 22 '17 at 18:52
7

My goal is to create a function that does the request and then returns the token

You cannot make a function that returns a value that it doesn't have immediately. You can only return a promise.

Then in some other part of code you can either wait for the promise to be fulfilled by using the then handler, or you can use something like:

var token = await getToken();

inside of an async function to wait for that value to be available, but only if the getToken() function returns a promise.

For example, using the request-promise module it would be something like:

var rp = require('request-promise');
function getToken() {
    // this returns a promise:
    return rp('http://www.example.com/some/path');
})

And then some other function:

function otherFunction() {
    getToken().then(token => {
        // you have your token here
    }).catch(err => {
        // you have some error
    });
}

Or, with async function something like this:

async function someFunction() {
    try {
        var token = await getToken();
        // you have your token here
    } catch (err) {
        // you have some error
    }
}

See: https://www.npmjs.com/package/request-promise

Note that async function and await is define in ECMAScript 2017 Draft (ECMA-262) which is not final yet at the time of this writing as of March 2017 (it will be in June 2017).

But it's already available in Node since v7.6 (and it was available since v7.0 if you used the --harmony flag). For the compatibility with Node versions, see:

If you want similar features for older Node versions with slightly different syntax, you can use modules like co or Promise.coroutine from Bluebird.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
rsp
  • 107,747
  • 29
  • 201
  • 177
  • 1
    [`request-promise` is now deprecated](https://www.npmjs.com/package/request-promise) – Liam Nov 10 '20 at 14:04
1

You can use javascript Promise or promise library like async

By javaScript promise:

new Promise((resolve, reject) => {
   resolve(getToken());
}).then(token =>{
    //do you rest of the work
    makeRequest(token);
}).catch(err =>{
   console.error(err)
})
Vishnu Mishra
  • 3,683
  • 2
  • 25
  • 36
0

You can use the feature of ES6 called generator. You may follow this article for deeper concepts. But basically you can use generators and promises to get this job done. I'm using bluebird to promisify and manage the generator.

Your code should be fine like the example below.

const Promise = require('bluebird');

function getToken(){
  return new Promise(resolve=>{
           //Do request do get the token, then call resolve(token).
         })
}

function makeRequest(token){
   return new Promise(resolve=>{
     //Do request do get whatever you whant passing the token, then call resolve(result).
   })
}

function* doAsyncLikeSync(){
  const token= yield getToken();  //After this function has finished
  const result = yield makeRequest(token);   //I want this function to be executed
  return result;
}

Promise.coroutine(doAsyncLikeSync)()
  .then(result => {
    //Do something with the result
  })