16

Fibers/Meteor.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();
    }
  });
}

これを初めて書いたとき、コールバックを Fiber() ブロックにラップする必要があるというエラーが発生しました。その後、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.

私はノードを初めて使用し、ファイバーの概念を完全には理解していません。私の理解では、スレッドは C/C++/スレッド化されたすべての言語のスレッドに似ていますが、サーバー側のコードに及ぶ影響が何であるか、または挿入しようとしたときにコードがエラーをスローする理由がわかりませんコレクション。誰かが私にこれを説明できますか?

ありがとうございました。

4

1 に答える 1

20

bindEnvironment を少し間違って使用しています。それが使用されている場所はすでにファイバー内にあり、Knox クライアントからのコールバックはもうファイバー内にないためです。

bindEnvironment には 2 つの使用例があります (私が考えることができるのは、他にもある可能性があります!)。

  • 変更する必要があるグローバル変数がありますが、他のユーザーのセッションに影響を与えたくない場合

  • サードパーティの api/npm モジュールを使用してコールバックを管理している (そのように見える)

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 には 1 つのスレッドしかありません。

ファイバーは、同時に実行できるイベントに似ていますが、待機タイプのシナリオ (インターネットからファイルをダウンロードするなど) がある場合に相互をブロックすることはありません。

したがって、同期コードを使用して、他のユーザーのイベントをブロックすることはできません。それらは順番に実行されますが、それでも単一のスレッドで実行されます。これは、Meteor がサーバー側に同期コードを持っている方法であり、それは何かを待つことができますが、他のユーザーはこれによってブロックされることはなく、別のファイバーでコードが実行されるため、何かを行うことができます。

Chris Mather は、これに関する優れた記事をhttp://eventedmind.comでいくつか公開しています。

Meteor.wrapAsync は何をしますか?

Meteor.wrapAsync最初のパラメーターとして指定したメソッドを受け取り、現在のファイバーで実行します。

また、コールバックをアタッチします (メソッドは、最初のパラメーターがエラーで、2 番目のパラメーターがfunction(err,result).

コールバックはバインドされMeteor.bindEnvironment、コールバックが起動されるまで現在のファイバーをブロックします。コールバックが起動するとすぐに、 を返すresultか、 をスローしerrます。

したがって、コールバックを使用してより深い関数をネストする代わりに、次の行でメソッドの結果を使用できるため、非同期コードを同期コードに変換するのに非常に便利です。また、bindEnvironment も処理するため、ファイバーのスコープが失われることを心配する必要はありません。

更新 Meteor._wrapAsyncは現在Meteor.wrapAsync文書化されています。

于 2013-11-15T06:43:49.793 に答える