Returning value from callback within Meteor.method

前端 未结 4 2082
别那么骄傲
别那么骄傲 2020-12-15 13:28

I am running into something I don\'t understand with Meteor. I have this method, which takes a query, sends it to amazon, and then in the callback of that function I try to

相关标签:
4条回答
  • 2020-12-15 13:48

    Meteor methods are asynchronous, you can get the result by many way.

    Using npm module fibers (The other answer are explaining it very clearly).

    There are some other way w/o using npm module :

    Via Session variable :

        Meteor.call('myMethod',args, function(error, result) { 
      if (error) { Session.set('result', error) } // Note that the error is returned synchronously 
      else { 
        Session.set('result', result) // Using : Session.get('result') will return you the result of the meteor call !
      }
    });
    

    Or Via template variable :

        Template.hello.onCreated(function helloOnCreated() {
      // counter starts at 0
      this.message = new ReactiveVar(0);
    });
    
    Template.hello.helpers({
      message() {
        return Template.instance().message.get();
      },
    });
    
    Template.hello.events({
      'click button'(event, instance) {
        Meteor.call('myMethod', args, function (error, result) {
          if (error) { Template.instance().message.set(error); }
          else {
            Template.instance().message.set(result);
          }
        })
      },
    });
    

    Hope it will help !

    0 讨论(0)
  • 2020-12-15 13:59

    For anyone new to Meteor seeing this question and wondering why a library like Future or Fiber is necessary, it's because that call to amazon.execute is asynchronous.

    In Javascript, many operations that take an extended period of time don't run one line after the next; Examples like writing to a database, using window.setTimeout, or making HTTP requests. With methods like these, historically you've needed to wrap the code you want to run after the fact in a callback.

    Future and Fibers provide syntactic sugar and additional functionality, but their core functionality is the same.

    Meteor uses special behind-the-scenes tricks to make certain built-in operations (like accessing MongoDB) appear synchronous, while still taking advantage of the increased performance of asynchronous code. For this reason, you normally only have to worry about async when using external packages (like the Amazon one in this example).


    Here's a fully fleshed-out example of using both Future and Fibers:

    There are some great articles explaining the nature of Sync/Async in Meteor on the Discover Meteor blog and at the Meteor Chef

    0 讨论(0)
  • 2020-12-15 14:00

    one better solution

    using Fiber package

    var Fiber = Npm.require('fibers');
    ...
    Meteor.methods({
        callAsync: function (args) {
            var fiber = Fiber.current;
    
            async(function (args) {
                ...
                fiber.run(res);
            });
    
            return Fiber.yield();
        }
    });
    
    0 讨论(0)
  • 2020-12-15 14:07

    You need to use Future to achieve your goal.

    How to use future since Meteor 0.6?

    Meteor.startup(function () {
     Future = Npm.require('fibers/future');
    
     // use Future here
    }
    

    Your method rewritten with Future:

    Meteor.methods({
     'search': function(query) {
    
        var future = new Future();
    
        amazon.execute('ItemSearch', {
                'SearchIndex': 'Books',
                'Keywords': query,
                'ResponseGroup': 'ItemAttributes'
        }, function(results) {
           console.log(results);
    
           future["return"](results)
    
        });
    
        return future.wait();
     }
    });
    

    Now it should work.

    Meteor.call('search', 'harry potter', function(error, response) {
       if(error){
        console.log('ERROR :', error);
       }else{
        console.log('response:', response);
       }
    
    });
    

    If you want to learn more about Future library I recommend watching screencast


    Update on 26/12/2017

    I just wanted to update this answer as you can achieve the same thing using promise and so, get rid of the "fibers" depedencies :)

    An example is worth a thousand words

    import scrap from 'scrap';
    
    Meteor.methods({
        'hof.add'(el) {
            check(el, {
                _link: String
            });
    
            const promise = getHofInfo(el._link)
                .then((inserter) => {
                    inserter.owner = Meteor.userId();
                    Hof.insert(inserter);
                    return true;
                })
                .catch((e) => {
                    throw new Meteor.Error('500', e.message);
                });
            return promise.await();
        }
    });
    
    
    function getHofInfo(_link) {
        return new Promise((resolve, reject) => {
            scrap(_link, function (err, $) {
                if (err) {
                    reject(err);
                } else {
                    const attakers = $('#report-attackers').find('li').text();
                    const defender = $('#report-defenders').find('li').text();
                    const _name = attakers + ' vs ' + defender;
                    const _date = new Date();
                    resolve({ _name, _date, _link });
                }
            });
        });
    }
    
    0 讨论(0)
提交回复
热议问题