Return value from callback to Meteor.method

I encounter what I do not understand with the help of the Meteor. I have this method that accepts a request, sends it to amazon, and then in the callback of this function I try to return the results.

Meteor.methods({ 'search': function(query) { var bookInfo; if (Meteor.isServer) { amazon.execute('ItemSearch', { 'SearchIndex': 'Books', 'Keywords': query, 'ResponseGroup': 'ItemAttributes' }, function(results) { bookInfo = results; console.log(bookInfo); return bookInfo; }); } } }); 

But when I put the following into the console in my browser (chrome):

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

I get the following:

 undefined response: undefined VM13464:3 

I think I understand that the first undefined comes from a method that returns nothing on the client, but the callback does not work at all.

amazon.execute (...) definitely returns something, as console.log writes the information I'm looking for right above the return.

Any ideas what is going wrong and how can I fix it?

+5
source share
4 answers

To achieve your goal you need to use the Future .

How to use the future with Meteor 0.6?

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

Your method is rewritten using 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 know more about the Future library, I recommend watching screencast


Update from 12/26/2017

I just wanted to update this answer, since you can achieve the same using the promise, and thus get rid of the β€œfiber” dependencies :)

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 }); } }); }); } 
+16
source

For any new meteor shower, this question is also interesting why a library like the future or fibers is necessary, this is because the call to amazon.execute is asynchronous.

In Javascript, many operations that take a long period of time do not start one line after the next; Examples include writing to a database, using window.setTimeout, or making HTTP requests. With such methods, historically you had to wrap the code that you want to run after the fact in a callback .

The future and the fibers provide syntactic sugar and additional functionality, but their basic functionality is the same.

Meteor uses special backstage techniques to make certain built-in operations (such as access to MongoDB) appear synchronously, at the same time, taking advantage of the increased performance of asynchronous code. For this reason, you usually have to worry about using asynchronous external packages (like Amazon in this example).


Here's a fully instantiated out example of using both Future and Fiber:

There are some great articles explaining the nature of Sync / Async on Meteor on the Discover Meteor blog and Cook Meteor.

+1
source

Meteor methods are asynchronous, you can get the result in many ways.

Using npm module modules (another answer explains this very clearly).

There is another way without using the npm module:

Through the 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 through a 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 this helps!

+1
source

one best solution

using the 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
source

Source: https://habr.com/ru/post/950885/


All Articles