2

私は Highland.js とリアクティブ プログラミングのスタイル全般が大好きです。私はコンテキストの喪失に苦しんでおり、状態を放棄することが目標であるモデルでコンテキストをエレガントに処理する方法を決定しようとしています。

例として、Amazon Web Services に自分のアカウントの配列があります。

var accounts = [{accessId:"12345","secretKey":"abc123","account":"foo"},
                {accessId:"34512","secretKey":"def456","account":"bar"}];

私の目標は、基本的に、リージョンで実行されているすべての EC2 インスタンスのスプレッドシートを作成することです。このようなもの。

Account   | Instance Size
--------- | -------------
foo       | m3.xlarge
foo       | c3.medium
bar       | t2.small

一般的なワークフローは次のようになります。

  1. 各アカウントを通過する
  2. ec2DescribeInstaces を呼び出す
  3. どういうわけか、各 ec2DescribeInstances コールを最終出力のアカウント名にマップします

通常の JavaScript では、ここでループを行うため、ec2DescribeInstances を呼び出すたびにコンテキストが存在します。

for ( account in accounts ) {
  var instances = ec2DescribeInstaces(account);
  for ( instance in instances ) {
    results.push({account:account.name, instanceSize: instance.size});
  }
}

リアクティブプログラミングで私が理解していることから、私はこのようなことをします

_(accounts)
 .map(ec2DescribeInstaces)
 .parallel(2)
 .each(function(result) {
   results.push(result);
 });

任意のガイダンス??? このチェーンの最後に、Amazon からのインスタンスがあります。しかし、それらをアカウントに関連付けて名前を取得する方法がわかりません。これをハックして値を取得できることはわかっていますが、ベストプラクティスとエレガントなものを探しています。

@Bergi、以下のように??? これは、必要なデータと Amazon から返されたデータの両方を含む「コンテキスト」オブジェクトを返すことが不可欠です。これに関する私の唯一の懸念は、チェーン全体でコンテキストを渡すと、呼び出しのために多くのデータの抜き取り、詰め込み、およびラッピングを行うことになるということです。

ec2DescribeInstances = _.wrapCallback(function(accountData, callback) {
  // we remove the extraneous account name using a pick
  var ec2 = new AWS.EC2(lodash.pick(accountData,'accessKeyId','secretAccessKey'));
  ec2.describeInstances({ Filters: [{Name:'instance-state-name', Values:['running']}] }, function(err,data) {
    if ( err ) return callback(err);
    // here I create an object that wraps the AWS response
    callback(null, {"account":accountData.alias, "data": data})
  });
});
4

2 に答える 2

1

_.zip()2 つのストリームを取り、ペアのストリームを返す を使用できます。したがって、ec2Instances を生成したストリームを例として使用します。

var ec2InstanceStream = _(accounts)
    .map(ec2DescribeInstaces)
    .parallel(2);

_(acounts).zip(ec2InstanceStream);
    .each(function(result) {
        //Each result: [{ /* original account */ }, { /* ec2 instance */ }]
        results.push(result);
    });

だから今、あなたはすべてを一緒に持っています。もちろん、もっと美しくすることもできます。たとえば、各ペアを 1 つのオブジェクトにマージする場合は、オブジェクトをマージするステップの.map(_.extend)前にを追加できます。.each()

于 2015-03-17T20:17:32.543 に答える
0

操作をネストして、スコープを取得します。

const h = require("highland");
const ec2DescribeInstaces = h.wrapCallback(function(account, cb) {
  return cb(null, [{
    size: account.size
  }, {
    size: ++account.size
  }]);
});

const accounts = [{
  size: 1, name: 1
}, {
  size: 2, name: 2
}, {
  size: 3, name: 3
}];

var results = [];
h(accounts)
  .map(account => {
    return ec2DescribeInstaces(account)
      .flatten()
      .map(instance => ({
        account: account.name,
        instanceSize: instance.size,
      }));
  })
  .parallel(2)
  .tap(results.push.bind(results))
  .collect()
  .toCallback(h.log)

accountこのようにして、そのインスタンスで作業している間、それぞれが関連している個人について引き続き知ることがinstanceでき、ストリームの結果がストリームであるため、ストリームは引き続き並行して実行されmapます。

さらに、これは広く適用可能なアプローチだと思います。返されるインスタンスの数や、アカウントごとに実行する操作の数は問題ではありません。たとえば、アカウントのインスタンスごとに 2 つの値をプッシュする必要がある場合はparallel(2)、 から 2 つのストリームを返すことができ、アプローチを完全に再調整する必要はなく、動作を微調整するだけです。mapresults

于 2016-09-21T01:06:00.780 に答える