Node.js v8.1 で util.promisify
っていう関数が追加されてたんですね。
古き良き伝統にしたがったコールバック形式の関数を Promise を返す形にしてくれる。つまり await 出来るようになる!
ということで、今時コールバック形式のライブラリなんて…と思ってたら azure-storage
がそれでした。
ということで使ってみよう。
使い方は簡単。
const f = util.promisify(hogehoge);
のようにコールバック形式の関数を渡してやると Promise を返す関数になるので…
await f();
とすれば OK。
じゃぁこんな感じに使えるかな。
import express from'express';import util from'util';import azure from'azure-storage';interface EntityType { PartitionKey: azure.TableService.EntityProperty<string>; RowKey: azure.TableService.EntityProperty<string>; Value: azure.TableService.EntityProperty<string>;}// Azure ストレージエミュレーターにつなぐconst client = azure.createTableService('AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;DefaultEndpointsProtocol=http;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;TableEndpoint=http://127.0.0.1:10002/devstoreaccount1;');asyncfunction getAll(){await util.promisify(client.createTableIfNotExists).bind(client)('test');const query =new azure.TableQuery().where('PartitionKey eq ?','a').select('Value');// 本当は util.promisify(client.queryEntities<EntityType>) みたいにしたかった。この場合どうするのが正解なんだろうreturnawait util.promisify(client.queryEntities).bind(client)('test', query,nullasany)as azure.TableService.QueryEntitiesResult<EntityType>;}const app = express(); app.get('/',async(req, res)=>{const result =await getAll(); res.json(result.entries.map(x => x.Value._));}); app.listen(3000);
注意点は、関数内部の this をちゃんと bind で指定してあげることくらいかな?
適当にデータつっこんだテーブルを用意して実行して localhost:3000 にアクセスすると…
返ってきた!!
実際使うとしたら都度都度 util.promisify するのではなく、都合のいい感じのラッパークラスを用意する感じかなぁ?
import express from'express';import util from'util';import azure from'azure-storage';interface EntityType { PartitionKey: azure.TableService.EntityProperty<string>; RowKey: azure.TableService.EntityProperty<string>; Value: azure.TableService.EntityProperty<string>;}// こういうラッパークラスにめんどくさい処理は押し込んでおいて…class TableService {constructor(private tableService: azure.TableService){}public createTableService = util.promisify(this.tableService.createTableIfNotExists).bind(this.tableService);private _queryEntities = util.promisify(this.tableService.queryEntities).bind(this);publicasync queryEntities<T>(tableName: string, query: azure.TableQuery, token: azure.TableService.TableContinuationToken){returnawaitthis._queryEntities(tableName, query, token)as azure.TableService.QueryEntitiesResult<T>;}}const innerClient = azure.createTableService('AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;DefaultEndpointsProtocol=http;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;TableEndpoint=http://127.0.0.1:10002/devstoreaccount1;');const client =new TableService(innerClient);asyncfunction getAll(){// 使う側は意識しなくてよくするawait client.createTableService('test');const query =new azure.TableQuery().where('PartitionKey eq ?','a').select('Value');returnawait client.queryEntities<EntityType>('text', query,nullasany);}const app = express(); app.get('/',async(req, res)=>{const result =await getAll(); res.json(result.entries.map(x => x.Value._));}); app.listen(3000);
まとめ
ライブラリー側で await 出来るように Promise 返してくれるようにしてほしさある。