albatrosary's blog

UI/UXとエンタープライズシステム

HTML5 Advent Calendar 3日目:最近気になっているHTML5の最新技術に触れてみました

このエントリーは「HTML5 Advent Calendar 2014」12月3日の記事です。私自身HTML5技術で気になっている機能をひと通り味見しましたので書き留めます。気になる機能は

  • Promise
  • ダイアログ要素
  • Web Animations API
  • Web Components

です。ダイアログ要素というのがかなりマニアックだと思いますが業務アプリケーションを作るときにはこういった機能が重要になってきます。

HTML5 Advent Calendar 2014 - Qiita

Promise

Promise は「非同期処理を抽象化したオブジェクトとそのオブジェクトを操作する仕組み」を提供します。MDNやHTML5 Rocksでも取り上げられています。Single-page Applicationを作るときは基本的にはRestful APIを使いデータを取得すると思います。例えば5個、10個あるプルダウンリストを個々に取得するとか、画面を出した後に一覧情報を取得するとか色々です。今風なアプリケーションはほとんど非同期でデータ取得を行うのではと思います。

Promise - JavaScript | MDN

JavaScript Promises: There and back again - HTML5 Rocks

Promise は現在 ES6のドラフトとして定義されています。各ブラウザの実装状況ですが次の通りです。

f:id:albatrosary:20141202144307p:plain

f:id:albatrosary:20141202144315p:plain

Promiseを試してみる

  var promise = new Promise(function(resolve, reject) {
    console.log('start!');
    if (true) {
      setTimeout(resolve, 1000, 'Stuff worked!');
    }
    else {
      reject(Error('It broke'));
    }
  });
  
  promise.then(function(result) {
    console.log(result);
  }, function(err) {
    console.log(err);
  });

  console.log('end!');

ここで、resolveとrejectは次の意味を持ちます:

Promise.resolve(value)

与えられた値で成功となる Promise オブジェクトを返します。もし値が thenable (then メソッドを持っているオブジェクト) ならば、返されるプロミスはその thenable に従い、その結果を採用します。そうでなければ、返されるプロミスは与えられた値で成功します。

Promise.reject(reason)

与えられた理由で失敗となる Promise オブジェクトを返します。

実際にブラウザのコンソールで実行させると次のような結果が得られます:

> start!
> end!
> Stuff worked!

エラーを発生させる場合はif(!true)とし評価すると次の結果が得られます。

> start!
> end!
> Error: It broke {stack: (...), message: "It broke"}

複数の Promise を束ねる

すべてのプロミスが終わった場合の評価

すべてのプロミスの処理が終了したときに何か処理を行いたい場合は「Promise.all」を使います。

Promise.all(iterable)

iterable 中の全てのプロミスが成功したときに成功するプロミスを返します。結果は全てのプロミスから得られた値の配列として渡されます。

  var p = new Promise(function(resolve, reject) { setTimeout(resolve, 500, 'one'); });
  var q = new Promise(function(resolve, reject) { setTimeout(resolve, 100, 'two'); });

  Promise.all([p, q]).then(function(value) {
    console.log(value);
  }).catch(function(err){
    console.log(err);
  });

結果は

> Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
> ["one", "two"]

エラーが発生した場合を確認します:

  var p = new Promise(function(resolve, reject) { setTimeout(resolve, 500, 'one'); });
  var q = new Promise(function(resolve, reject) { setTimeout(reject, 100, Error('It broke'))});

  Promise.all([p, q]).then(function(value) {
    console.log(value);
  }).catch(function(err){
    console.log(err);
  });

結果は

> Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
> Error: It broke {stack: (...), message: "It broke"}

プロミスのどれかが終わった場合の評価

定義したプロミスのうち、どれかが終了した場合に何か処理を行わせる場合には「Promise.race」を利用します。

Promise.race(iterable)

iterable 中のプロミスの内、最初に完了 (成功または失敗) したプロミスによって成功または失敗するプロミスを返します。

  var p = new Promise(function(resolve, reject) { setTimeout(resolve, 500, 'one'); });
  var q = new Promise(function(resolve, reject) { setTimeout(resolve, 100, 'two'); });

  Promise.race([p, q]).then(function(value) {
    console.log(value);
  }).catch(function(err){
    console.log(err);
  });

結果は次のようになります:

> Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
> two

ダイアログ要素

ダイアログ要素はページ内ダイアログ機能を提供します。ダイアログは DOM ツリー内に存在し、通常の CSS でスタイリングすることができるそうです。

dialog element demo

ダイアログの処理

JavaScriptの定義

ダイアログをモーダルとして表示し入力された値を親画面に返却する処理を記載します。

(function() {
  // ダイアログの定義
  var dialog = document.querySelector('dialog');

  // ダイアログ表示ボタン
  var show = document.querySelector('#show');
  show.addEventListener('click', function() {
    dialog.showModal();
    console.log('dialog opened');
  });

  // ダイアログの操作
  document.querySelector('#close').onclick = function() {
    var value = document.querySelector('#return_value').value;
    dialog.close(value);
  };
  document.querySelector('dialog').addEventListener('close', function() {
    console.log(this.returnValue);
  });
})();

CSSの定義

このダイアログは普通にHTMLですからカスケードスタイルシートも定義できます。

dialog {
  border: 1px solid rgba(0, 0, 0, 0.3);
  border-radius: 6px;
  box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
}

HTMLの定義

肝心のHTMLでは下記のように定義しています。

      <dialog>
        <p>This is da dialog!</p>
        <input type="text" id="return_value" value="" placeholder="Enter value">
        <button id="close">Enter</button>
      </dialog>
      <button id="show">Open Dialog!</button>

Web Animations API

ウェブアニメーションはウェブ上でアニメーション化されたコンテンツを駆動するための新しいJavaScript APIです。 SVGCSSのアニメーション機能を統一することで、ウェブアニメーションは開発者に強力で高性能なアニメーション機能が提供されます。

Web Animations

Web Animations API の Polyfill

Web Animations API には現状ポリフィルが提供されています。

web-animations/web-animations-js · GitHub

このライブラリを使ったデモがあるのでぜひ見てください。なんとなく Material Designに似てるのは気のせいでしょうか?

http://web-animations.github.io/web-animations-demos/

f:id:albatrosary:20141202153054p:plain

Web Components

Web Components はHTMLを部品化する仕組みで次の4つの要素かな成り立っています。

  • Custom Elements
  • HTML Templates
  • HTML Imports
  • Shadow DOM

Custom Elementsは独自のタグを定義し、 HTML TemplatesでHTMLを部品化します。部品化したHTMLをHTML Importsにより読み込みます。もっとも重要な要素がShadow DOMでこれによりDOMがカプセル化されます。サンプルは以前こちらに記載しましたので合わせて御覧ください。

Web標準だけでHTMLを部品化するWeb Componentsを試してみる - albatrosary's blog

【続】Web標準だけでHTMLを部品化するWeb Componentsを試してみる - albatrosary's blog

最後に

HTML5はまだまだこれからアプリケーション開発に必要な技術が盛りだくさんで展開されます。まさにWebがプラットフォームになる日も近いと感じられます。今のうちに色々な技術を習得しておくのは吉かと思います。