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
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 !
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
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();
}
});
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 });
}
});
});
}