[英]Trying to understand Promise()
因此,我分叉了一個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
。
第一個,當我從AWS很好地獲取數據點時,getMetricStatistics函數可以很好地工作。
函數本身:
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 Metrics:
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 [未定義]
好的,所以我沒有返回then
的calculateMovingAverage()。 它解決了未定義的錯誤。 我仍然沒有從putAverageMetricData()函數獲取日志,這讓我覺得我仍然缺少一些東西。
我希望有人能指出我正確的方向
您的getMetricStatistics
和putAverageMetricData
方法已經返回了Promise
,因此請避免在calculateMovingAverage
使用Promise
構造函數反模式 ! 並且不要忘了從那里最終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);
});
}
在calculateMovingAverage
您必須返回正在創建的承諾,否則Promise.all
無法確定承諾何時得到解決。
return promisedland.then((results) => {
...
}).catch(...);
除了向您提供有關如何修復此代碼的直接答案之外,我還將向您提供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
})
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.