Meteor.wrapAsync Over Specific NPM Package Method?

I can’t figure out how to wrap geocoder so it is synchronous…


import geocoder from 'geocoder';

let geoCoderAsync = Meteor.wrapAsync(geocoder.reverseGeocode);

let result = geoCoderAsync(data.location.latitude, data.location.longitude, function ( err, response ) {
      if (err) { console.log(err); }
      return result
});

console.log(result)

this outputs

TypeError: Cannot read property ‘reverseGeocode’ of undefined

Wrap geocoder with a promise, then await the result.

Remember to use the Promise package via Promise.await()

Is there any reason wrapAsync can’t work here?

so this package? https://atmospherejs.com/meteor/promise

Can you provide a quick example using my above code? I’m not familiar with this.

'addThing': function(data){
let callback = (err, response ) => {
      if (err) { console.log(err); }
      let location = response;
      return location;
    };

    const getLocation = () => {
      return new Promise(geocoder.reverseGeocode(data.latitude, data.longitude, callback));
    }

    let location = Promise.await(getLocation());

   console.log(location());
}

this results in

TypeError: Promise.asyncApply is not a function

To the best of my understanding, there are at least 2 ways of dealing with sync data in Meteor: Fibers and Promises. Fibers are native to Node.js and work only on server, whereas Promises (with async/await syntax) is a super-new JavaScript approach and should technically work on both server and client. Specifically wrapAsync is based on Fibers and actually works only on server. So depending on your requirements, if, for example, you do not need client synchronous code, you can perfectly live with Fibers.

I can give you an example of a working sync method with wrapAsync, maybe it can guide you into right direction (the method should run only on server):

Meteor.methods({
  test(value) {
    const wrapped = Meteor.wrapAsync(function(value, callback){
      Meteor.setTimeout(function () {
        callback(null, value);
      }, 3000);
    });
    return wrapped(value);
  },
});

Now if you call this method on client:

  Meteor.call('test', 'hello world', function(error, result){
    console.log('test', result);
  });

…you will get response in 3 sec.

When investigating Promises I could not properly show the result of a promise in a helper with native Meteor and did not want to install any third party packages. If someone could share a working simple example that can be easily repeated/followed, would be good.

1 Like

try let callback = ( response, err )

Meteor.methods({

  'addThing': function(latitude,longitude ){

    let callback = (response, err ) => {

      if (err) { throw new Meteor.Error('geocoder-failed', 'geocoder failed'); }

      return response;
    };

    const getLocation = () => {
      return new Promise.async(geocoder.reverseGeocode(latitude, longitude, callback));
    }

    let location = Promise.await(getLocation());

  console.log(location)

  },

this still gives me TypeError: Promise.asyncApply is not a function

is there any reason i can’t use wrapAsync here?

Are there any examples using the promise package? The repo has zero.

  ` return new Promise [CORRECT PROMISE SYNTAX] `

you are are not using promises correctly.

okay… so this?

Meteor.methods({

  'addThing': function(latitude,longitude ){

    let callback = (response, err ) => {

      if (err) { throw new Meteor.Error('geocoder-failed', 'geocoder failed'); }

      return response;
    };

    const getLocation = () => {
      return new Promise geocoder.reverseGeocode(latitude, longitude, callback));
    }

    let location = Promise.await(getLocation());

  console.log(location)

  },

can you take a minute and provide a quick code example? It’s hard to piece together your comments one by one.

You have to use resolve reject. Simply go online or even better buy a book (the secrets of the javascript ninja, or eloquent javascript), and practice with promises. Knowing javascript grammar is important to avoid such problems, as it’s a bit tricky.

I’m at work, sorry if I can’t help you better, here’s one of my promises:

`

return new Promise((resolve, reject) => {

            longrunningfunction( (err, resp) => {

                if (err) {
                    console.log('Data Error :', err)
                    reject(err);
                }

                resolve(resp);

            });

`

plus

'addThing': function(data){

should be

'addThing': async function(data){

trust me, stop using meteor. Take an ES6 course, or stop using ES6 syntax.

Okay thanks.

Does anyone know why Meteor.wrapAsync isn’t working here? I used it on a similar situation with the stripe API and it works great.

You seem to have mixed up sync and async syntax. I’d write it like this:

import geocoder from 'geocoder';

let reverseGeocodeSync = Meteor.wrapAsync(geocoder.reverseGeocode, geocoder);

try {
  const result = reverseGeocodeSync(data.location.latitude, data.location.longitude);
  console.log(result);
} catch (err) {
  throw new Meteor.Error('oops', 'something bad happened');
}
2 Likes

Rob Fallows for President 2016!!!

:slight_smile: Thanks, but I just had to edit a typo, so I’m not worthy.

I saw that. It’s okay… it works!

TRUMP + FALLOWS 2016.

MAKE METEOR GREAT AGAIN

1 Like

Just to confirm, the key here is to pass the method to be used AND the top-level object holding the method?

so

let reverseGeocodeSync = Meteor.wrapAsync(geocoder.reverseGeocode, geocoder);

not

let reverseGeocodeSync = Meteor.wrapAsync(geocoder);

and not

let reverseGeocodeSync = Meteor.wrapAsync(geocoder.reverseGeocode);

W-e-e-e-e-ll … not always. It all depends on what the wrapped method expects in the way of binding. Having said that, I’ve found that 90% of the time it’s fine with it, whether or not it “needs” it.

So, I took a chance that it would be OK. You should try without the binding to see if it still works. :slight_smile: