AWS SDK for javascriptを使って、AWSのリソース情報を取得し、その情報を以て何らかの処理を実行する際に、取得した結果を変数に格納して、それを表示しようとしたのですが、APIは非同期であるため、API実行と非同期で、APIの結果が帰って来る前に、変数に格納されている値が表示されてしまうので、値が取得できませんでした。
調べてみるとPromiseと言われる機能がNode.jsにあって、これを使うことによって、同期ぽく処理できるということを知りました。(Promiseの中が非同期でそれぞれ実行されるので、厳密には、同期ではない)
そこで今回は、「EBSボリュームの一覧を取得する」というの例として、Promiseを使って実装して見たいと思います。
Promiseをthenで繋ぐ書き方
一番簡単な方法がPromiseでresolveをthenで数珠つなぎに書く方法です。
const AWS = require('aws-sdk'); const ec2 = new AWS.EC2({region: 'ap-northeast-1'}); new Promise(function(resolve, reject) { resolve(ec2.describeVolumes().promise()); }) .then((volumeList) => { console.log(volumeList); });
resolveを空にしてthenに処理を書く
上ソースをちょっときれいに書くため、resolveは敢えて空にして処理を全てthen以降に書いてます。
const AWS = require('aws-sdk'); const ec2 = new AWS.EC2({region: 'ap-northeast-1'}); Promise.resolve() .then(() => { return ec2.describeVolumes().promise(); }) .then(response => { volumeList = response; console.log(volumeList); });
関数化する
さらに、AWS SDKのAPIを叩く部分を関数化することで、よりシンプルになります。
const AWS = require('aws-sdk'); const ec2 = new AWS.EC2({region: 'ap-northeast-1'}); let volumeList; Promise.resolve() .then(() => { return getEc2Volume(); }) .then(res => { volumeList = res; }); function getEc2Volume() { return ec2.describeVolumes().promise(); }
Promise + ジェネレータ(co)を使う
個人的に一番簡潔な書き方が、Promiseとジェネレータを使って書く方法です。
yieldを関数の前に書くことで、関数のreturnが返却されるまで待機してから後続の処理をします。
const AWS = require('aws-sdk'); const ec2 = new AWS.EC2({region: 'ap-northeast-1'}); const co = require('co'); co(function *() { let volumeList = yield getEc2Volume(); console.log(volumeList); }); function getEc2Volume() { return ec2.describeVolumes().promise(); }
以上