所以我已经分叉了一个Javascript项目并尝试扩展它,同时从中学习。我的Javascript技能真的很新鲜,但我认为这很有趣。然而,我正在努力应对所有的承诺,以至于我有许多承诺和风格,我真的不明白它是如何定位的。我没有得到最终结果而且无法理解为什么。
所以我从头开始(我禁用了一个功能以保持简单):
export const calculateMovingAverage = (event, context, callback) =>
Promise.all([
// ma.calculateMovingAverage('Kraken', 'AskPrice'),
ma.calculateMovingAverage('Coinbase', 'SellPrice'),
])
.then((tx) => {
console.log('tx', tx);
}).catch((err) => {
console.error('err', err);
callback({ statusCode: 500, body: { message: 'Something went wrong' } });
});
因此调用ma.calculateMovingAverage()
:
calculateMovingAverage(exchange, metric) {
const self = this;
const args = {
minutes: 10,
period: 60,
currency: `${self.cryptoCurrency}`,
metricname: `${metric}`,
localCurrency: `${self.localCurrency}`,
namespace: `${exchange}`,
};
var promisedland = new Promise((resolve, reject) => {
self.cloudwatch.getMetricStatistics(args, (err, data) => {
if (err) { return reject(err); }
if (!Array.isArray(data.Datapoints) || !data.Datapoints.length) { return reject("No Datapoints received from CloudWatch!")}
data.Datapoints.forEach(function(item) {
self.ma.push(item.Timestamp, item.Average);
});
resolve(ma.movingAverage());
})
})
promisedland.then((results) => {
return new Promise((resolve, reject) => {
const body = {
value: results,
metricName: `${metric} @ 180 MovingAverage`,
namespace: `${exchange}`
};
self.cloudwatch.putAverageMetricData(body, function(err, result) {
if (err) { return reject(err); }
resolve(result);
});
}
)
}).catch(function(err) {
return reject(err);
});
}
现在您可以在calculateMovingAverage()中看到,我尝试调用两个AWS方法。 getMetricStatistics
和putAverageMetricData
。
第一个,getMetricStatistics函数可以很好地工作,因为我很好地从AWS中获取了Datapoints。
功能本身:
getMetricStatistics(args) {
return this.cloudwatch.getMetricStatistics({
EndTime: moment().subtract(180, 'minutes').utc().format(),
Dimensions: [
{
Name: 'CryptoCurrency',
Value: args.currency
},
{
Name: 'LocalCurrency',
Value: args.localCurrency
},
{
Name: 'Stage',
Value: process.env.STAGE || 'dev'
}
],
MetricName: args.metricname,
Period: Number(args.period),
StartTime: moment().subtract(190, 'minutes').utc().format(),
Statistics: ['Average'],
Unit: 'Count',
Namespace: args.namespace || 'Coinboss',
}).promise();
}
接下来我想通过MovingAverage模块传递响应,并希望通过putAverageMetricData函数将MA的结果放入CloudWatch指标:
putAverageMetricData(args) {
return this.cloudwatch.putMetricData({
MetricData: [
{
MetricName: args.metricName,
Timestamp: moment().utc().format(),
Unit: 'Count',
Value: Number(args.value),
},
],
Namespace: args.namespace || 'Coinboss',
}).promise()
.then(function(result) {
console.log('putAverageMetricData', result);
});
}
这是我迷路的地方。我看起来数据永远不会到达putAverageMetricData函数。控制台输出仅向我显示 console.log('tx', tx);
以及以下内容:
2017-07-15T19:37:43.670Z 118ff4f0-6995-11e7-8ae7-dd68094efbd6 tx [ 未定义]
好的,所以我没有返回calculateMovingAverage()then
。它解决了未定义的错误。我仍然没有从putAverageMetricData()函数中获取日志,这让我觉得我还在遗漏一些东西。
我希望有人能指出我正确的方向
答案 0 :(得分:1)
您的getMetricStatistics
和putAverageMetricData
方法已经返回承诺,因此请避开calculateMovingAverage
中的Promise
constructor antipattern!并且最后不要忘记return
承诺:
calculateMovingAverage(exchange, metric) {
const args = {
minutes: 10,
period: 60,
currency: this.cryptoCurrency,
metricname: metric,
localCurrency: this.localCurrency,
namespace: exchange,
};
return this.cloudwatch.getMetricStatistics(args).then(data => {
if (!Array.isArray(data.Datapoints) || !data.Datapoints.length)
throw new "No Datapoints received from CloudWatch!";
for (const item of data.Datapoints) {
this.ma.push(item.Timestamp, item.Average);
}
return this.ma.movingAverage();
}).then(results => {
const body = {
value: results,
metricName: `${metric} @ 180 MovingAverage`,
namespace: exchange
};
return this.cloudwatch.putAverageMetricData(body);
});
}
答案 1 :(得分:0)
在calculateMovingAverage
中,您必须返回您正在创建的承诺,否则Promise.all
无法告知承诺何时解决。
return promisedland.then((results) => {
...
}).catch(...);
答案 2 :(得分:0)
我没有直接回答如何修复此代码,而是会给你Promises 101课程,我认为你将能够理解更高层次的内容。
JavaScript(通常)是“单线程”,意味着一次只能执行一行代码。有时,我们需要做的事情很长,比如向我们的服务器发出请求。为了解决这个问题,javascript使用了回调函数。回调函数是将函数作为参数传递给另一个函数时。最基本的例子是settimout函数。
setTimeout(function() {
// settimout takes a callback function
}, 1000);
现在,回调的神奇之处在于它将不会被执行,直到所有其他“非回调”代码或“同步”代码
setTimeout(function(error, goodStuff) {
console.log("WHAAT WHY AM I SECOND?") //this gets printed second
}, 1000);
console.log("YAY! I GET TO GO FIRST!!!!") // this is printed first
这称为javascript事件循环。这是我做的一个小图片,让您了解它是什么:
正如您所看到的那样,调用堆栈和异步队列。所有不是回调或异步的代码都将转到调用堆栈。同步特朗普函数将切断线并首先运行。回调函数将转到消息队列或事件循环,并等待所有同步函数完成。同步函数的调用堆栈完成后,回调将开始执行。但最终,javascript程序员遇到了一个小问题。
Javascript开始变得越来越复杂,最终,回调开始进行回调。他们越是嵌套,他们就越难读。看看这个眼睛疼痛:
fs.readdir(source, function (err, files) {
if (err) {
console.log('Error finding files: ' + err)
} else {
files.forEach(function (filename, fileIndex) {
console.log(filename)
gm(source + filename).size(function (err, values) {
if (err) {
console.log('Error identifying file size: ' + err)
} else {
console.log(filename + ' : ' + values)
aspect = (values.width / values.height)
widths.forEach(function (width, widthIndex) {
height = Math.round(width / aspect)
console.log('resizing ' + filename + 'to ' + height + 'x' + height)
this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
if (err) console.log('Error writing file: ' + err)
})
}.bind(this))
}
})
})
}
})
所以为了让这样的东西更容易阅读,承诺诞生了!代码就像上面的回调一样,让它逐行阅读。
myfirstPromise().then((resultFromFirstPromise) => {
return mySecondPromise();
}).then((resultFromSecondPromise) => {
return myThirdPromise();
}).then((resultFromThirdPromise) => {
//do whatever with the result of the third promise
}).catch((someError) => {
//if any of the promises throw an error it will go here!
})
因此,将这些概念应用于您的代码,这就是我们想要做的事情:
getMetricStatistics(options)
.then(metricStatistics => {
// do what you need to do with those stats
return putAverageMetricData(metricStatistics);
})
.then((putMetricDataResult => {
//do what you need to do with the metric data result
}))
.catch(err => {
//do error stuff
})