DEV Community

Jan Küster
Jan Küster

Posted on • Edited on

Async Meteor Method calls

Meteor is mostly backward compatible to even < 1.0 projects. Therefore lots of code is still callback based. So is the Meteor.call method. You can easily wrap it into a Promise-based approach:

export const callMethod = ({ name, args }) => 
  new Promise((resolve, reject) => {
    Meteor.call(name, args, (error, result) => {
      if (error) {
        return reject(error)
      }

      return resolve(result)
    })
})
Enter fullscreen mode Exit fullscreen mode

Although Meteor.call supports multiple arguments I rather prefer to pass a single object with named arguments to keep the code more expressive.

You can then use callMethod natively in an async environment:

Template.myTemplate.events({
  'click .some-button': async function (event, templateInstance) {
    const age = await callMethod({
      name: 'getAge', 
      args: { name: 'John Doe' }
    })
    console.log(age) // whatever the method returned
  }
})
Enter fullscreen mode Exit fullscreen mode

Additionally you can "hook" into these calls and thus mix callbacks with promises and create a decent UX experience when method calls are part of user interactions:

export const callMethod = ({ name, args, prepare, receive, success, failure }) => {
  // before call
  if (typeof prepare === 'function') {
    prepare()
  }

  // create the promise
  const promise = new Promise((resolve, reject) => {
    Meteor.call(name, args, (error, result) => {
      // on received
      if (typeof receive === 'function') {
        receive()
      }

      if (error) {
        return reject(error)
      }

      return resolve(result)
    })
  })

  // on success
  if (typeof success === 'function') {
    promise.then(success)
  }

  // on error
  if (typeof failure === 'function') {
    promise.catch(failure)
  }

  return promise
}
Enter fullscreen mode Exit fullscreen mode

The code can then be used for example to display a "waiting" indicator:

Template.myTemplate.events({
  'click .update-button': async function (event, templateInstance) {
   const updatedDoc = await callMethod({
     name: 'updateUser', 
     args: { name: 'John Doe', age: 42 },
     prepare: () => templateInstance.state.set('updating', true),
     receive: () => templateInstance.state.set('updating', false),
     failure: er => alert(er),
     success: () => alert('updated')
   })
   // process updatedDoc if desired
})
Enter fullscreen mode Exit fullscreen mode


I regularly publish articles here on dev.to about Meteor and JavaScript. If you like what you are reading and want to support me, you can send me a tip via PayPal.

You can also find (and contact) me on GitHub, Twitter and LinkedIn.

Keep up with the latest development on Meteor by visiting their blog and if you are the same into Meteor like I am and want to show it to the world, you should check out the Meteor merch store.

Top comments (0)