Возвращаемое значение из обратного вызова в Meteor.method
Я сталкиваюсь с чем-то, что я не понимаю с Метеором. У меня есть этот метод, который принимает запрос, отправляет его в Amazon, а затем в обратном вызове этой функции я пытаюсь вернуть результаты.
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;
});
}
}
});
Но когда я вставляю в консоль своего браузера (chrome) следующее:
Meteor.call('search', 'harry potter', function(error, response) {
console.log('response:', response);
});
Я получаю это:
undefined
response: undefined VM13464:3
Мне кажется, я понимаю, что первое неопределенное происходит от метода, который ничего не возвращает клиенту, но обратный вызов, похоже, не работает вообще.
Amazon.execute (...) определенно что-то возвращает, так как console.log прямо над return записывает искомую информацию.
Есть идеи, что происходит и как я могу это исправить?
4 ответа
Вам нужно использовать будущее, чтобы достичь своей цели.
Как использовать будущее, начиная с Meteor 0.6?
Meteor.startup(function () {
Future = Npm.require('fibers/future');
// use Future here
}
Ваш метод переписан с 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();
}
});
Теперь это должно работать.
Meteor.call('search', 'harry potter', function(error, response) {
if(error){
console.log('ERROR :', error);
}else{
console.log('response:', response);
}
});
Если вы хотите узнать больше о библиотеке будущего, я рекомендую посмотреть скринкаст
Обновление от 26.12.2017
Я просто хотел обновить этот ответ, так как вы можете достичь того же, используя обещание и, таким образом, избавиться от зависимостей "волокон":)
Пример стоит тысячи слов
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 });
}
});
});
}
Метеоритные методы асинхронны, вы можете получить результат разными способами.
Использование волокон модуля npm (другой ответ объясняет это очень четко).
Есть другой способ без использования модуля npm:
Через переменную сеанса:
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 !
}
});
Или через переменную шаблона:
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);
}
})
},
});
Надеюсь, это поможет!
Для любого новичка в Метеоре, который видит этот вопрос и задается вопросом, зачем нужна такая библиотека, как Future или Fiber, это потому, что этот вызов amazon.execute является асинхронным.
В Javascript многие операции, которые занимают длительный период времени, не запускают одну строку после следующей; Примеры, такие как запись в базу данных, использование window.setTimeout или выполнение HTTP-запросов. С помощью таких методов исторически вам нужно было обернуть код, который вы хотите запустить после факта, в обратный вызов.
Future и Fibers предоставляют синтаксический сахар и дополнительную функциональность, но их основная функциональность одинакова.
Meteor использует специальные закулисные приемы, чтобы определенные встроенные операции (например, доступ к MongoDB) выглядели синхронными, но при этом все еще использовали преимущества повышенной производительности асинхронного кода. По этой причине вам обычно приходится беспокоиться только об асинхронности при использовании внешних пакетов (например, Amazon в этом примере).
Вот подробный пример использования Future и Fibers:
Есть несколько замечательных статей, объясняющих природу Синхронизации / Асинхронизации в Метеоре, в блоге Discover Meteor и в Meteor Chef.
используя пакет Fiber
var Fiber = Npm.require('fibers');
...
Meteor.methods({
callAsync: function (args) {
var fiber = Fiber.current;
async(function (args) {
...
fiber.run(res);
});
return Fiber.yield();
}
});