我正在遇到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会记录我正在寻找的信息。
任何想法出了什么问题以及如何解决它?
您需要使用Future来实现您的目标。
自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 });
}
});
});
}
对于任何刚接触Meteor的人来看这个问题并想知道为什么像Future或Fiber这样的库是必要的,这是因为对amazon.execute的调用是异步的。
在Javascript中,许多需要较长时间的操作在下一个操作之后不会运行一行;例如写入数据库,使用window.setTimeout或发出HTTP请求。使用这些方法,历史上你需要在回调中包装你想要运行的代码。
Future和Fibers提供语法糖和附加功能,但它们的核心功能是相同的。
Meteor使用特殊的幕后技巧使某些内置操作(如访问MongoDB)看起来是同步的,同时仍然利用异步代码的增强性能。因此,在使用外部程序包时(例如本示例中的Amazon程序包),通常只需要担心异步。
Here是使用Future和Fibers的完全充实的例子:
有一些很棒的文章解释了the Discover Meteor blog和the Meteor Chef上Meteor中同步/异步的本质
流星方法是异步的,你可以通过多种方式获得结果。
使用npm模块光纤(另一个答案非常清楚地解释)。
还有其他方法没有使用npm模块:
通过Session变量:
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);
}
})
},
});
希望它会有所帮助!
使用光纤包
var Fiber = Npm.require('fibers');
...
Meteor.methods({
callAsync: function (args) {
var fiber = Fiber.current;
async(function (args) {
...
fiber.run(res);
});
return Fiber.yield();
}
});