我在使用Fibers/Metor.bindEnvironment()时遇到了困难。如果集合开始为空,我会尝试更新代码并插入到集合中。这一切都应该在启动时在服务器端运行。
function insertRecords() {
console.log("inserting...");
var client = Knox.createClient({
key: apikey,
secret: secret,
bucket: 'profile-testing'
});
console.log("created client");
client.list({ prefix: 'projects' }, function(err, data) {
if (err) {
console.log("Error in insertRecords");
}
for (var i = 0; i < data.Contents.length; i++) {
console.log(data.Contents[i].Key);
if (data.Contents[i].Key.split('/').pop() == "") {
Projects.insert({ name: data.Contents[i].Key, contents: [] });
} else if (data.Contents[i].Key.split('.').pop() == "jpg") {
Projects.update( { name: data.Contents[i].Key.substr(0,
data.Contents[i].Key.lastIndexOf('.')) },
{ $push: {contents: data.Contents[i].Key}} );
} else {
console.log(data.Contents[i].Key.split('.').pop());
}
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
if (Projects.find().count() === 0) {
boundInsert = Meteor.bindEnvironment(insertRecords, function(err) {
if (err) {
console.log("error binding?");
console.log(err);
}
});
boundInsert();
}
});
}我第一次写这篇文章的时候,我遇到了需要将回调封装在纤程()块中的错误,然后在IRC上的讨论中,有人建议尝试使用Meteor.bindEnvironment(),因为这应该放在纤程中。这并不起作用(我看到的唯一输出是inserting...,这意味着bindEnvironment()没有抛出错误,但它也不会运行代码块中的任何代码)。然后我得到了这个。我现在的错误是:Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.
我是Node的新手,并不完全理解Fibers的概念。我的理解是,它们类似于C/C++/每种带有线程的语言中的线程,但我不明白扩展到我的服务器端代码的含义是什么/为什么我的代码在尝试插入到集合时抛出错误。有人能给我解释一下吗?
谢谢。
发布于 2013-11-15 14:43:50
您对bindEnvironment的使用略有错误。因为它的使用位置已经在纤程中,而从Knox客户端传出的回调不再在纤程中。
bindEnvironment有两个用例(我能想到的可能还有更多!):
Meteor.bindEnvironment创建一个新的纤程,并将当前纤程的变量和环境复制到新纤程中。当您使用您的nom模块的方法回调时,您需要这样做。
幸运的是,还有一种替代方法可以处理等待您的回调,并将该回调绑定到一个名为Meteor.wrapAsync的纤程中。
所以你可以这样做:
您的启动函数已经有了一个纤程,并且没有回调,所以这里不需要bindEnvironment。
Meteor.startup(function () {
if (Projects.find().count() === 0) {
insertRecords();
}
});和您的插入记录函数(使用wrapAsync),因此不需要回调
function insertRecords() {
console.log("inserting...");
var client = Knox.createClient({
key: apikey,
secret: secret,
bucket: 'profile-testing'
});
client.listSync = Meteor.wrapAsync(client.list.bind(client));
console.log("created client");
try {
var data = client.listSync({ prefix: 'projects' });
}
catch(e) {
console.log(e);
}
if(!data) return;
for (var i = 1; i < data.Contents.length; i++) {
console.log(data.Contents[i].Key);
if (data.Contents[i].Key.split('/').pop() == "") {
Projects.insert({ name: data.Contents[i].Key, contents: [] });
} else if (data.Contents[i].Key.split('.').pop() == "jpg") {
Projects.update( { name: data.Contents[i].Key.substr(0,
data.Contents[i].Key.lastIndexOf('.')) },
{ $push: {contents: data.Contents[i].Key}} );
} else {
console.log(data.Contents[i].Key.split('.').pop());
}
}
});有几件事需要牢记。纤维和线不一样。NodeJS中只有一个线程。
纤程更像是可以同时运行的事件,但如果存在等待类型的场景(例如,从互联网下载文件),则不会相互阻塞。
因此,您可以使用同步代码,而不会阻塞其他用户的事件。它们轮流运行,但仍然在单个线程中运行。这就是为什么Meteor在服务器端有同步代码,可以等待东西,但其他用户不会被阻塞,可以做东西,因为他们的代码运行在不同的纤程中。
Chris Mather在http://eventedmind.com上有几篇关于这方面的好文章
Meteor.wrapAsync是做什么的?
Meteor.wrapAsync接受您提供的方法作为第一个参数,并在当前纤程中运行它。
它还附加了一个回调(它假设该方法接受最后一个参数,该参数有一个回调,其中第一个参数是错误的,第二个参数是结果,比如function(err,result)。
回调与Meteor.bindEnvironment绑定,阻塞当前的纤程,直到触发回调。一旦触发回调,它就会返回result或抛出err。
因此,它对于将异步代码转换为同步代码非常方便,因为您可以在下一行使用方法的结果,而不是使用回调和嵌套更深的函数。它还会为您处理bindEnvironment,因此您不必担心丢失光纤的范围。
更新 Meteor._wrapAsync现在是Meteor.wrapAsync和documented。
https://stackoverflow.com/questions/19994951
复制相似问题