Onsen UI: ons.readyについて

  • 5
    いいね
  • 0
    コメント

Onsen UIは、最初からハイブリッドモバイルアプリケーション用に作られたため、Cordovaと組み合わせた場合の実装がなされています。そこで、今回はアプリを起動したときの最初の処理であるons.readyについて調べてみました。

Cordovaの初期化処理とdevicereadyイベント

そもそも、Cordovaの場合、cordova.jsが読み込まれると、初期化処理がはじまります。初期化処理には、アプリのネイティブ部分(AndroidならJava、iOSならObjective-C)の初期化処理と、各種プラグインの初期化処理があり、それがすべて完了すると、devicereadyイベントが発火します。

cordova-jsのソースコードは
https://github.com/apache/cordova-js
にありますが、この中でcommon/initモジュール
https://github.com/apache/cordova-js/blob/master/src/common/init.js
が、初期化処理を担う部分です。そして、このコードの一番下の方に、

    channel.join(function() {
        require('cordova').fireDocumentEvent('deviceready');
    }, channel.deviceReadyChannelsArray);

とあります。ここでdevicereadyを発火していたんですね。ちなみに、channel.deviceReadyChannlsArrayは、

[channel.onNativeReady, channel.onPluginsReady]

という、ネイティブの初期化処理とプラグインの初期化処理からなる配列です。

Onsen UIのons.readyメソッド

さて、Onsen UIの初期化処理は 
https://github.com/OnsenUI/OnsenUI/blob/master/core/src/ons/ons.js
にコードがあります。最初の方でonsオブジェクトが定義されていきますが、その最後で

    ons._readyLock = new DoorLock();

    ons.platform.select((window.location.search.match(/platform=([\w-]+)/) || [])[1]);

    waitDeviceReady();

というコードがあります。ここ定義されている_reayLockというのが初期化完了したかどうかを判定するオブジェクトですね。そして、waitDeviceReady()メソッドにより、Onsen UIの初期化が完了するまで待機に入ります。

Onsen UIの初期化が完了したかどうかを判定するためのメソッドとしてons.isReady()
というメソッドがありますが、その実装は、単に_readyLockオブジェクトに問い合わせているだけです。_readyLockオブジェクトがロックされいたら、まだ初期化が終わっていないことになります。

ons.isReady = () => {
  return !ons._readyLock.isLocked();
};

では、waitDeviceReady()はどのようになっているかというと、

function waitDeviceReady() {
  const unlockDeviceReady = ons._readyLock.lock();
  window.addEventListener('DOMContentLoaded', () => {
    if (ons.isWebView()) {
      window.document.addEventListener('deviceready', unlockDeviceReady, false);
    } else {
      unlockDeviceReady();
    }
  }, false);
}

これを見ると分かる様に、まずDOMContentLoadedイベントを待ってから、

  1. もしCordovaアプリなら(ons.isWebView()が真なら)、さらにdevicereadyイベントを待ち、その後unlockDeviceReady_readyLockオブジェクトのロックを解除します。

  2. もしCordovaアプリでないなら、ただちにunlockDeviceReady_readyLockオブジェクトのロックを解除します。

それでは肝心のons.readyメソッド自体はどうなっているのでしょうか?
コードを見てみると

ons.ready = callback => {
  if (ons.isReady()) {
    callback();
  } else {
    ons._readyLock.waitUnlock(callback);
  }
};

となっていました。すでに初期化処理が終わっていたらただちにcallbackを実行し、そうでないなら、waitUnlockメソッドでcallbackを登録して、_readyLockオブジェクトが解除された時にcallbackが実行されるように設定しています。

まとめ

ということで、Cordovaを組み込んだ時のons.readyはCordovaのdevicereadyイベントを受け取って
から発火することがわかりました。ということは、もし何らかの原因で、Cordovaのdevicereadyイベントが発火しなかった場合(プラグインに問題があるなど)すると、ons.readyも同時に発火しなくなってしまいます。ons.readyイベントが発火しない場合は、Cordovaプラグインについても確認してみましょう。

また、waitDeviceReadyについてですが、DOMContentLoadedイベントで判定しているので、HTMLのソースコードは読み込みが完了していて、DOM操作もできる状態になっているのですが、アプリの最初のページをJQueryやAngularなどでレンダリングしている場合、それが終わっているとは限りません。というか、基本的に終わっていません。
このため、ons.readyが終わったからといって、即、1ページ目が完全に表示されているわけではないので、イベントリスナーなどの処理をするには早い場合があります。ページごとの初期化処理は、initイベントで実装するようにしましょう。

この投稿は Onsen UI Advent Calendar 20163日目の記事です。