我遇到了Meteor不理解的事情。我有这个方法,它接受查询,将其发送到亚马逊,然后在该函数的回调中我尝试返回结果。
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
我想我明白第一个undefined来自于在客户端上没有返回任何内容的方法,但回调似乎根本不起作用。
amazon.execute(...)肯定会返回一些内容,因为返回正上方的console.log会记录我正在寻找的信息。
任何想法出了什么问题以及如何解决它?
答案 0 :(得分:18)
您需要使用未来来实现目标。
自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);
}
});
如果您想了解有关未来库的更多信息,我建议您观看screencast
2017年12月26日更新
我只是想更新这个答案,因为你可以使用promise来实现同样的东西,所以,摆脱"纤维"依赖:)
一个例子胜过千言万语
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 });
}
});
});
}
答案 1 :(得分:1)
对于Meteor的新用户看到这个问题并想知道为什么像Future或Fiber这样的库是必要的,这是因为对 amazon.execute 的调用是异步的。
在Javascript中,许多花费较长时间的操作在下一个操作之后不会运行一行;例如写入数据库,使用 window.setTimeout 或发出HTTP请求。使用这些方法,从历史上看,您需要在回调中包装您想要运行的代码。
Future和Fibers提供语法糖和附加功能,但它们的核心功能是相同的。
Meteor使用特殊的幕后技巧来使某些内置操作(如访问MongoDB)出现同步,同时仍然利用异步代码的增强性能。因此,在使用外部软件包时(例如本示例中的Amazon软件包),您通常只需要担心异步。
Here是使用Future和Fibers的完全充实的例子:
有一些很棒的文章在the Discover Meteor blog和the Meteor Chef
上解释了流星中同步/异步的本质答案 2 :(得分:1)
Meteor方法是异步的,你可以通过多种方式获得结果。
使用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);
}
})
},
});
希望它会有所帮助!
答案 3 :(得分:0)
使用光纤包
var Fiber = Npm.require('fibers');
...
Meteor.methods({
callAsync: function (args) {
var fiber = Fiber.current;
async(function (args) {
...
fiber.run(res);
});
return Fiber.yield();
}
});