我喜欢Highland.js和一般的反应式编程风格。我正在为失去上下文而挣扎,我正在努力确定如何在一个目标是放弃状态的模型中优雅地处理上下文。
例如,我在中有一个帐户数组。
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一般的工作流程是
在普通的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);
});有指引吗?在这条链的末尾,我看到了亚马逊的例子。但我不知道怎么把这些和账户联系起来才能知道名字。我知道我可以绕过这些来获得价值,但我正在寻找最佳实践和一些优雅的东西。
所以@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})
});
});发布于 2015-03-17 20:17:32
您可以使用_.zip(),它接受两个流并返回成对的流。因此,以生成ec2Instances的流为例:
var ec2InstanceStream = _(accounts)
.map(ec2DescribeInstaces)
.parallel(2);
_(acounts).zip(ec2InstanceStream);
.each(function(result) {
//Each result: [{ /* original account */ }, { /* ec2 instance */ }]
results.push(result);
});所以现在你把一切都放在一起了。你当然可以做得更好。例如,如果要将每一对对象合并为单个对象,可以在.each()步骤之前添加一个.each(),以便将这些对象合并在一起。
发布于 2016-09-21 01:06:00
我会嵌套这些操作以获得一些范围:
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)通过这种方式,您仍然了解每个instance在处理该实例时与之相关的单个instance,而且由于map的结果是一个流,所以流仍然将并行运行。
此外,我认为这是一个广泛适用的方法。无论您返回了多少个实例,或者您想为每个帐户做多少事情都无关紧要。例如,如果您需要为帐户上的每个实例将两个值推送到parallel(2),您可以从map返回两个流,并且您不需要完全调整您的方法,只需要调整行为。
https://stackoverflow.com/questions/29108401
复制相似问题