简体   繁体   中英

Using a Variable Out of Scope of a Callback Function in Node.js / Express.js

I am using a library called node-geocoder in express js which has the following code:

var NodeGeocoder = require('node-geocoder');

var options = {
  provider: 'google',

  // Optional depending on the providers
  httpAdapter: 'https', // Default
  apiKey: 'YOUR_API_KEY', // for Mapquest, OpenCage, Google Premier
  formatter: null         // 'gpx', 'string', ...
};

var geocoder = NodeGeocoder(options);

// Using callback
geocoder.geocode('29 champs elysée paris', function(err, res) {
  console.log(res);
});

The response variable(res) in the geocode method's callback function holds an object with location properties such as latitutde and longitude. The link for this package is here

I was wondering if there was a way to use that response variable outside of the callback function in the geocode method. I need to pull the latitude and longitude properties and I don't want to keep the rest of the code within that callback function.

As a noob I tried just returning the object and storing it in a variable like so:

var object = geocoder.geocode('29 champs elysée paris', function(err, res) {

   return res;

});

This doesn't work since it's in the callback and not returned in the actual geocode method.

Not directly, but there are a couple of options to get closer to that.

One would be to have your callback be a defined function and use that as the callback:

const doSomething = (err, res) => { /* do something */ }

geocoder.geocode('abc', doSomething);

Not really much different, but can make it a little cleaner.

You can also "promisify" the function to have it return a Promise . Something like this would do the trick:

const geocodePromise = (path) => new Promise((resolve, reject) => {
    geocoder.geocode(path, (err, res) => err ? reject(err) : resolve(res));
});

geocodePromise('abc')
  .then(res => { /* do something */ })
  .catch(err => { /* do something */ });

Finally, if you are using Babel for transpiling (or Node version 7.6.0 or higher, which has it natively), you can use async and await . Using the same promisified version of the function as above, you'd have to wrap your main code in an async function. I generally use a self-calling anonymous function for that:

(async () => {
  try {
    const res = await geocodePromise(path);

    /* do something with res */
  } catch (err) {
    /* do something with err */
  }
})();

With this, you get the closest to what you want, but you'll still have to wrap your main code up in a function because you can't await at the top level.

You can use the response of your function outside the callback by calling another function.

geocoder.geocode('29 champs elysée paris', function(err, res) {
  if(!err){
    // call a function if there is no error
    console.log(res);
    myFunction();
  }
 });

function myFunction(){
 //do your processing here
}

I don't want to keep the rest of the code within that callback function.

The code doesn't have to be in the callback, it just has to be called from the callback.

So you write your function (or functions) as normal:

function handleInfo(info) {
    doSomethingWithInfo(info);
    doSomethignElse(info);
    // ...
}
// ...

...and then call those functions when you have the data:

geocoder.geocode('29 champs elysée paris', function(err, info) {
  if (err) {
      // Handle error
  } else {
      handleInfo(info);
  }
});

geocode can return promise already, no need to re-wrap it. If you don't care about the error and just want to grab the response's location data. You can do this

var locationData = geocoder.geocode('29 champs elysée paris').then( function(res){
    return res;
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM