以前に書いた、こちらのエントリ。
InfinispanのJavaScriptクライアント(Hot Rod)を試してみる - CLOVER
InfinispanのJavaScriptクライアントを使って、チュートリアルを参考に書いてみたエントリなのですが、どうにもPromiseの扱いが読みづらくて書き直してみようかなと。
書き直すにあたり、こういうコンセプトでいくことにしました。
- あんまりPromiseをネストさせない(前がすごく読みづらかったのは、これが大きい)
- Babelを使ってECMAScript 2015で書く
- テストコードとして実行する(Mocha+Chai)
というわけで、参考にしたり使ったりしたライブラリは、このあたり。
GitHub - infinispan/js-client: Javascript client for Infinispan, over the Hot Rod wire protocol
準備
必要なnpmモジュールをインストールします。
$ npm install --save-dev infinispan mocha chai babel-register babel-preset-es2015
依存関係は、こんな感じで。
"devDependencies": { "babel-preset-es2015": "^6.6.0", "babel-register": "^6.7.2", "chai": "^3.5.0", "infinispan": "^0.2.0", "mocha": "^2.4.5" }
また、Mochaでテストを動かす前にBabelを使うので、Babelのドキュメントを設定にこのように設定。
"scripts": { "test": "mocha --compilers js:babel-register" },
.babelrcも用意。
$ echo '{ "presets": ["es2015"] }' > .babelrc
テストの実行は、以下のコマンドになります。
$ npm run test
テストコードの雛形
テストコードの全体の枠としては、以下のように作成。
test/infinispan-js-client-test.js
const infinispan = require("infinispan"); const should = require("chai").should(); describe("Infinispan JavaScript Client, Getting Started Test", () => { // ここに、テストを書く! }
とりあえず、書き直してみる
何も考えずに、前に書いたコードをECMAScript 2015+Mocha+Chaiで書き直すと、こんな感じに。
※clientメソッドの引数は、前のバージョンから指定方法が変わったようです
it("minimal.", () => { return infinispan.client({ host: "localhost", port: 11222 }).then(client => { console.log("connected."); // put return client.put("key1", "value1") // get and verify .then(() => client.get("key1").then(value => value.should.equal("value1"))) // replace .then(() => client.replace("key1", "value100")) // put .then(() => client.put("key2", "value2")) // get and verify .then(() => client.get("key1").then(value => value.should.equal("value100"))) // get and verify .then(() => client.get("key2").then(value => value.should.equal("value2"))) // put all .then(() => client.putAll([ { key: "key3", value: "value3" }, { key: "key4", value: "value4" }, { key: "key5", value: "value5" } ])) // get all and verify .then(() => client.getAll(["key1", "key2", "key3", "key4", "key5"]).then(entries => { entries.length.should.equal(5); const sorted = entries.sort((a, b) => a.key.substring(3) - b.key.substring(3)); sorted[0].should.deep.equal({ key: "key1", value: "value100" }); sorted[1].should.deep.equal({ key: "key2", value: "value2" }); sorted[2].should.deep.equal({ key: "key3", value: "value3" }); sorted[3].should.deep.equal({ key: "key4", value: "value4" }); sorted[4].should.deep.equal({ key: "key5", value: "value5" }); })) // clear .then(() => client.clear()) // size and verify .then(() => client.size().then(size => size.should.equal(0))) // disconnect .finally(() => { console.log("disconnect."); return client.disconnect(); }); }); });
Promiseをthenでつなげていくスタイルですが、getしたものについてはそのままthenでアサーションするようにしています。
前に書いたコードよりは、コールバックがあまり深くならず、だいぶ見やすくなった気がします(本人目線)。
なお、前回はこれでした。
var infinispan = require("infinispan"); var connected = infinispan.client(11222, "localhost"); connected.then(function(client) { console.log("connected."); var putted1 = client.put("key1", "value1"); var getted1 = putted1.then(function() { return client.get("key1").then(function(value) { console.log("key1 = " + value); }); }); var replaceAndPut = getted1.then(function() { return client .replace("key1", "value100") .then(function() { return client.put("key2", "value2"); }); }); var getted2 = replaceAndPut.then(function() { return client .get("key1") .then(function(value) { console.log("key1 = " + value); }) .then(function() { return client.get("key2").then(function(value) { console.log("key2 = " + value); }); }) }); var putAll = getted2.then(function() { return client.putAll([ { key: "key3", value: "value3" }, { key: "key4", value: "value4" }, { key: "key5", value: "value5" } ]) }); var getAll = putAll.then(function() { return client .getAll(["key1", "key2", "key3", "key4", "key5"]) .then(function(entries) { console.log("entries = " + JSON.stringify(entries)); }); }); return getAll.then(function() { console.log("clear"); return client.clear(); }).finally(function() { return client.disconnect().then(function() { console.log("disonnected"); }); }); });
アサーションも次のthenで
先の結果だと、前の関数の結果を次の関数で引き継げないようにも見えてしまうので、アサーションを次のthenに与えた関数で実行するようにもうひとつパターンを書いてみました。
it("pass callback value.", () => { return infinispan.client({ host: "localhost", port: 11222 }).then(client => { console.log("connected."); // put return client.put("key1", "value1") // get .then(() => client.get("key1")) // get result verify .then(value => value.should.equal("value1")) // replace .then(() => client.replace("key1", "value100")) // put .then(() => client.put("key2", "value2")) // get .then(() => client.get("key1")) // get result verify .then(value => value.should.equal("value100")) // get .then(() => client.get("key2")) // get result verify .then(value => value.should.equal("value2")) // put all .then(() => client.putAll([ { key: "key3", value: "value3" }, { key: "key4", value: "value4" }, { key: "key5", value: "value5" } ])) // get all .then(() => client.getAll(["key1", "key2", "key3", "key4", "key5"])) // get all result verify .then(entries => { entries.length.should.equal(5); const sorted = entries.sort((a, b) => a.key.substring(3) - b.key.substring(3)); sorted[0].should.deep.equal({ key: "key1", value: "value100" }); sorted[1].should.deep.equal({ key: "key2", value: "value2" }); sorted[2].should.deep.equal({ key: "key3", value: "value3" }); sorted[3].should.deep.equal({ key: "key4", value: "value4" }); sorted[4].should.deep.equal({ key: "key5", value: "value5" }); }) // clear .then(() => client.clear()) // size .then(() => client.size()) // size result verify .then(size => size.should.equal(0)) // disconnect .finally(() => { console.log("disconnect."); return client.disconnect(); }); }); });
ちょっと長くなってしまいましたが、ちゃんと直前のPromiseで得た結果が次の関数に渡せています。
Promiseをつなげるにあたって
JavaScript界隈でPromiseをどう扱うのが今のスタイルなのか、よくわかっていません。
ちょっと調べて、highlandやbluebirdを使うのかなとも思ったのですが、今回はうまく使えず挫折しました…。
Node.jsフロー制御 Part 1 – コールバック地獄 vs. Async vs. Highland | POSTD
素でPromiseを使うよりも、楽な方法ってあるでしょうか?
なお、Infinispan JavaScriptクライアントで使っているPromiseは、どうやらこちらのようです。
GitHub - then/promise: Bare bones Promises/A+ implementation
まとめ
以前に書いたInfinispanのJavaScriptクライアントを使ったコード例を、ECMAScript 2015を使ったりテストコードとして書き直してみました。
InfinispanのJavaScriptクライアントのAPIの最新化についてはまだちゃんと追っていないので、そのうち。
今回作成したコードは、こちらに置いています。
https://github.com/kazuhira-r/infinispan-getting-started/tree/master/remote-js-client-with-es2015-rewrited