LoginSignup
8
2

More than 5 years have passed since last update.

BaaS@rakuzaのCordovaプラグインをPromiseに対応させる

Posted at

BaaS@rakuzaのCordovaプラグイン(RKZClient)の各関数は非同期処理のため、引数に成功時・失敗時のコールバック関数を受け取るようになっています。
そのため、A処理をしてからB処理をする場合に、処理がネストしてソースコードが見づらくなってしまいます。(いわゆる、コールバック地獄)
エラー処理が何度も出てくるし、微妙・・

MainController.js
RKZClient.setTenantKey(TENANT_KEY, function() {
  // 初期化が終わったら、ユーザーを登録
  var userData = {};
  RKZClient.registUser(userData, function(userData) {
    // ユーザー登録が終わったらプッシュ通知の初期化(デバイストークンの登録)
    setupPushNotification(userData.user_access_token);
  }, function () {
    // エラー処理
  });
}, function(error) {
  // エラー処理
});

引数にコールバック関数を受け取る方法ではなく、Promiseを返す様にしたら解決します。
以下のようなイメージ
エラー処理も1つにまとまり、すっきり

MainController.js
setTenantKey().then(function() {
  // 初期化が終わったら、ユーザーを登録
  var userData = {};
  return registUser(userData);
}).then(function (userData) {
  // ユーザー登録が終わったらプッシュ通知の初期化(デバイストークンの登録)
  setupPushNotification(userData.user_access_token);
}).catch(function(error) {
  // エラー時にアラートでエラー内容を表示します
  alert(JSON.stringify(error, null, ' '));
});

function setTenantKey() {
  var deferred = $q.defer();

  RKZClient.setTenantKey(TENANT_KEY, function() {
    deferred.resolve();
  }, function(error) {
    deferred.reject(error);
  });

  return deferred.promise;
}

function registUser(userData) {
  var deferred = $q.defer();

  RKZClient.registUser(userData, function(userData) {
    deferred.resolve(userData);
  }, function(error) {
    deferred.reject(error);
  });

  return deferred.promise;
}

ただ、RKZClient呼び出すごとにPromiseでラップする処理を書くのは面倒です。
そこで、RKZClient自体をラップしてみます。ついでに、PromiseはES2015のオブジェクトを使います。

RKZClientPromise
(function (global) {
  global.document.addEventListener('deviceready', onDeviceReady);

  function onDeviceReady() {
    var originalClient = global.RKZClient;

    // RKZClientの各関数をProxy関数で上書き
    // (RKZClientのプロトタイプのプロパティのみ処理していることに注意)
    Object.keys(Object.getPrototypeOf(originalClient)).filter(function (key) {
      return typeof originalClient[key] === 'function';
    }).forEach(function (key) {
      console.log(key);
      originalClient[key] = createProxy(originalClient[key]);
    });

    function createProxy(originalFunc) {
      return function () {
        var args = Array.prototype.slice.call(arguments);
        var handlers = args.filter(function (arg) {
          return typeof arg === 'function';
        });
        // ハンドラーが引数にある場合は、元の関数を実行
        if (handlers.length != 0) {
          return originalFunc.apply(this, args);
        }
        // ハンドラーが引数にない場合は、Promiseを返す
        return new Promise(function (resolve, reject) {
          args.push(function () {
            resolve.apply(this, arguments);
          });
          args.push(function () {
            reject.apply(this, arguments);
          });
          originalFunc.apply(this, args);
        });
      };
    }
  }
})(window);
index.html
<script>
  ons.bootstrap('myApp');
</script>
<script src="js/RKZClientPromise.js"></script> <!-- MainController.jsより先に読み込む -->
<script src="js/controllers/MainController.js"></script>

これで、RKZClientの各関数がPromiseを返す様になります。

MainController.js
RKZClient.setTenantKey(TENANT_KEY).then(function() {
  // 初期化が終わったら、ユーザーを登録
  var userData = {};
  return RKZClient.registUser(userData);
}).then(function (userData) {
  // ユーザー登録が終わったらプッシュ通知の初期化(デバイストークンの登録)
  setupPushNotification(userData.user_access_token);
}).catch(function(error) {
  // エラー時にアラートでエラー内容を表示します
  alert(JSON.stringify(error, null, ' '));
});

Promiseに対応していないライブラリがあれば、同じ様にラップしてみても良いかもしれません。
※公式が対応してくれるのが一番ですが

8
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
2