コンテンツへスキップ

縦長のWebサイトに。ヘッダー固定化ライブラリ

スマートフォンなど画面が小さい場合、Webサイトはどうしても縦長になりがちです。そしてスクロールを下まで行い、別なページに移ろうと思うと今度は上までスクロールし続けないといけません。これは非常にストレスです。

そこで使ってみたいのがヘッダー部分を固定表示してくれるライブラリです。ヘッダー情報へのアクセスがしやすくなるのでユーザビリティが高くなるでしょう。

simple-sticky-header

以下のようなシンプルなコードでヘッダー固定化を実現します。デザインがスクロール時には変更されます。


fixednav({id:"outer-id", nav:"nav-id", distance:40, down:50, up:200, delay:70});

view raw

index.js

hosted with ❤ by GitHub

cara-tm/simple-sticky-header: Very simple javascript & CSS fixed header on scroll down based on an element’s height.

AnimatedHeader

スクロールするとヘッダーが小さくなるアニメーションとともに固定化されます。若干実装が複雑になっています。

codrops/AnimatedHeader: A fixed header that will animate its size on scroll. The inner elements will also adjust their size with a transition.

partly-fixed-header

ヘッダーではなく広告を常時表示するのを想定して作られています。とは言えメニューなどに変更して使うこともできるはずです。

skimmet/header: A head that is only fixed when scrolled past the banner.

aheader

上にスクロールする際にヘッダーを表示するというタイプのライブラリです。ユーザが下までコンテンツを見た後、上に戻る操作をしたタイミングでヘッダー情報が出せます。

Peleg/aheader: Fixed header on scrolling up


こうしたライブラリを使うと画面上の一部分は常に情報が表示され、そこを使えなくなってしまいます。画面が十分に大きい場合はいいですが、4インチくらいの画面サイズであまり大きなヘッダーは却って邪魔になってしまう可能性があります。小さくユーザビリティを損なわないライブラリを選ぶか、二段階くらいのサイズ変化に対応しているものを選ぶと良いでしょう。

DeviceConnectを使ったハンズオンを開催しました

3月20日にDeviceConnectをhifiveから使うハンズオンを開催しました。

hifive x DeviceConnectによるWoT体験ハンズオン! – connpass

DeviceConnectというのはスマートフォンアプリで、スマートフォン内にHTTPサーバを立てます。そのHTTPサーバを使って、スマートフォンに繋がっている各種デバイス(THETA、Pebble、Hueなど)をWeb API経由で操作できる技術になります。

Device Connectとは? – Qiita

今回はデスクトップ側のHTMLファイルからDeviceConnectに接続し、スマートフォンの操作(バイブレーションやライトなど)を行うハンズオンを開催しました。資料はオンラインで公開しています。

hifivemania/deviceconnect-handson

DeviceConnectを使うためにはローカルネットワークが使えないといけないため、ハンズオン会場でルータを設置する必要がありました。また、本来であればデバイスを操作すると楽しいのですが、全員がHueなどを持っている訳ではないので、今回はスマートフォンの機能を操作するだけに留めています。DeviceConnectを知った上で、自分の持っているデバイスを操作してみて欲しいです。

今回のハンズオンではhifiveのコントローラ、並びにロジックを体験してもらいました。ロジックを使うことで非同期処理を分かりやすく、再利用性高く実装できます。hifiveには他にもたくさんの機能がありますので、ぜひ使ってみてください。

約10名の方に参加いただき、皆さんにhifiveはもちろん、DeviceConnectを使ったWoTの実現方法について学んでもらうことができました。hifiveではこれからもハンズオンを開催していきますので、ぜひご参加ください。

hifive – connpass

HTML5.2で何が変わるのか

HTML5.1が勧告され、すでにW3Cの活動は5.2策定に向けて動き始めています。コンマ1の違いなので、大幅に変わるわけではありませんが、現状に合わせて多少の変更が行われるようです。

実際の勧告案はHTML 5.2にて確認できます(最終アップデートは2017年12月14日)。具体的なHTML5.1との違いは HTML 5.2: Changes にて確認できますが、今回は簡単にまとめてみました。以下の内容はあくまでも執筆時点のものであり、変わる可能性もあります。

menuタグのtoolbarの廃止

現状、Webブラウザでサポートしているものがないようで、このままいくとHTML5.2ではなくなるようです。

dialog タグの廃止

こちらも実装されているブラウザがない(Operaだけ実装されている模様)ようで、このまま進むと廃止対象になります。

複数のAPIの廃止

以下のAPIが廃止されます。

  • registerContentHandler
    Webサイトを特定のMIMEタイプに関連付ける。
  • isContentHandlerRegistered
    特定のMIMEタイプに関連づけられているかどうか判定する。
  • isProtocolHandlerRegistered
    URLスキームとURLを引数として、そのハンドラー状態を返す。

input type=datetime 、 inputmode の廃止

フォーム入力系としてはこの二つがなくなる可能性があります。

keygenタグの廃止

Web Crypto APIの登場に伴ってGoogle Chromeでは削除されています。他のブラウザではまだ使えるようですが、他も追従していくものと思われます。


基本的には以上のようにタグや要素の廃止が多いようです。Webブラウザで元々実装されていなかったものもあるので、仕様を最適化していると思われます。動作ががらっと変わることはないでしょうが、今後のWeb標準の変化を知るためにもチェックしておきましょう。

HTML 5.2

ユーザの入力ストレスを軽減するライブラリまとめ

フォーム入力は必要とは言え、ユーザにとってストレスの大きい仕組みです。特にスマートフォンやタブレットで多くの入力項目を埋めるのは苦労が伴うでしょう。それだけにサーバに送って入力エラーがあると、ユーザは修正するのが嫌になってしまうかも知れません。

そこで使ってみたいのが今回紹介するクライアントサイドでの入力チェックライブラリです。リアルタイムに入力チェックを行ったり、そのメンテナンスを簡単にしてくれるライブラリが多数あります。

json-editor

JSONスキーマからフォームを生成します。JSONスキーマでは入力タイプであったり、入力できる文字列長なども指定できます。それらの設定に基づいて自動的にフォームを生成し、入力チェックも行ってくれます。

jdorn/json-editor: JSON Schema Based Editor

Winterfell

独自のJSONフォーマットからフォームを生成し、入力チェックも行うReact用のライブラリになります。独自のJSON記法を覚える必要がありますが、ステップ踏んで進むようなフォームも生成できるようです。

andrewhathaway/Winterfell: Generate complex, validated and extendable JSON-based forms in React.

formAnimation

バリデーションでエラーがあった際にフォーム全体を揺らすライブラリです。バリデーション自体はjQuery Validateを使っています。

nnluukhtn/formAnimation: Form Animation: when form validation <3 animate.css

tlx-editor

入力チェックを兼ね備えたWebコンポーネントライブラリです。一行テキスト、テキストエリア、ラジオ、チェックボックス、セレクト、スターレーティングなど幅広く対応しています。

anywhichway/tlx-editor: A single HTML component supporting all input types, select, textarea, radio groups, and star ratings.

Hyperform

HTML5のバリデーションAPIの完全実装を目指して作られているライブラリです。IE9についても利用できるようになっています。将来的にHTML5のバリデーションが標準化された後もそのまま使い続けられそうです。

hyperform/hyperform: Capture form validation back from the browser

jq-idealforms

基本的なバリデーションに加えて日付ピッカーやステップ、Ajaxによるサーバ側とのデータ検証など幅広い入力チェックに対応しています。ブラウザもIE9以降で利用できます。

elclanrs/jq-idealforms: The ultimate framework for building and validating responsive HTML5 forms.

jquery.formance

入力フォーマット(クレジットカードや電話番号など)を指定することで、入力チェックと必要に応じてハイフン(-)などを自動入力してくれます。

omarshammas/jquery.formance: A jQuery library for formatting and validating form fields, based on Stripe’s jQuery.payment library.

Creditly

クレジットカード番号の入力チェックに特化したライブラリです。カード会社を判別して、それによってセキュリティコードの桁数を変えたり、チェックデジットの検証も行います。

wangjohn/creditly: An intuitive credit card form


入力チェックはサーバ側でも行う必要があるため、クライアントに特化しすぎているとサーバ側でのエラーチェックと差異が発生したり、メンテナンスが煩雑になります。JSONスキーマのような設定ファイルを使うことで、サーバとクライアント両方で共通したバリデーションが可能になるでしょう。

フォーム入力を改善、便利にしてくれるライブラリまとめ

フォーム入力というのはユーザにとってストレスの大きい仕組みです。やたらと項目が多かったり、選択肢が多数あると途中で適当な入力になってしまうかも知れません。それは業務システムでも言えます。

そこでなるべくユーザストレスを減らせるようなライブラリを紹介します。これらを使えばフォーム入力の手間や煩雑さが改善されるはずです。

floatlabels.js

スマートフォンでは入力項目のところにあらかじめ何を入力すれば良いかプレースホルダーという仕組みで文字が表示されていますが、ユーザが入力を開始すると消えてしまって不便です。floatlabels.jsではプレースホルダーを別な場所にアニメーションしながら移動してくれるので忘れてしまったりすることなく入力が続けられるようになります。

probots-io/floatlabels.js: Follows the famous Float Label Pattern. Built on jQuery.

fontIconPicker

Web Fontを使った入力補完ライブラリです。絵文字入力とはまた違った使い勝手になります。ユーザにアイコンを選択して欲しい時に使うと便利そうです。

micc83/fontIconPicker: jQuery fontIconPicker v2 is a small (3.22kb gzipped) jQuery plugin which allows you to include a simple icon picker with search and pagination inside your administration forms.

paperstencil

PDF並の細かな表示にこだわったフォームが生成できます。作成ツールも用意されていますので、文章を書いたり入力欄を作ったりするのも簡単にできます。表を使った段組にも対応しています。

bitstat/paperstencil: A cross between word processor and web form. Paperstencil helps enterprises to roll-out data collection solutions, contracts, signatures, payment related solutions of their business needs in few minutes.

Garlic.js

入力内容をlocalStorageに保存しておき、再読込時に入力を再現してくれるライブラリです。入力項目が多い場合など、誤った削除でせっかくの入力内容がすべてなくなってしまったりするのを防げます。

guillaumepotier/Garlic.js: Automatically persist your forms’ text and select field values locally, until the form is submitted.

formBuilder

ドラッグ&ドロップでフォームを作成できるライブラリです。生成した内容をデータベースなどに保存しておくことで、ユーザが自分自身で自由にフォームを作れるようになります。お問い合わせフォームのような汎用的なフォームで、ユーザがカスタマイズしたいといった時に使えます。

kevinchappell/formBuilder: A jQuery plugin for drag and drop form creation

Multi-Step-Form-Js

フォーム入力を複数の段階に分けたマルチステップにしてくれるライブラリです。本当のフォームは一つしかありませんので、サーバサイドに送られるのはすべて入力した後になります。入力項目が多い場合に使えます。

mgildea/Multi-Step-Form-Js: Multi Step Form with jQuery validation

formbase

フォームの表示をスタイルシートだけで見栄えのいいものにデザインしてくれます。HTMLは標準のままなので、作業不要です。単純なHTMLでデザインが当たっていない状態であれば、formbaseを使って少しでも使い勝手を向上すると良いでしょう。

electerious/formbase: Better default styles for common input elements.


見た目を整えるだけでもフォーム入力はしやすくなります。さらにJavaScriptによって改善できるポイントは多いでしょう。これらのライブラリを使いこなせばユーザにとって使いやすいフォームが簡単に実現できるはずです。

Web Workerをインラインで使う

HTML5 APIで追加されつつも、あまり使われている雰囲気がないのがWeb Workerではないでしょうか。使い方はそれほど難しい訳ではないですが、別途JavaScriptファイルを用意したりするのが面倒に感じられるのかも知れません。JavaScriptではできない、並列処理を行うためには必須のAPIです。

そこで手軽に使えるようにインラインのちょっとしたコードをWeb Worker化してみたいと思います。

サンプルのコード

例えば次のようなコードをWeb Worker化します。 e はメインスレッドから渡されるイベントで、 e.data でメッセージを受け取れます。メインスレッドからは onmessage が呼ばれますので、処理を行った上で postMessage で返せばOKです。


onmessage = (e) => {
setTimeout(() => {
postMessage('Workerからの返信です。' + e.data);
}, 2000);
}

view raw

index.js

hosted with ❤ by GitHub

このコードを文字列にします。


const code = `
onmessage = (e) => {
setTimeout(() => {
postMessage('Workerからの返信です。' + e.data);
}, 2000);
}
`;

view raw

index.js

hosted with ❤ by GitHub

Blob化する

次にこの文字列をBlobにします。


const blob = new Blob();
const blobURL = URL.createObjectURL(blob);

view raw

index.js

hosted with ❤ by GitHub

ワーカーにする

後はこのblobURLをワーカーとして指定するだけです。


const worker = new Worker(blobURL);

view raw

index.js

hosted with ❤ by GitHub

これで準備完了です。

実行する

後はメインスレッドからpostMessageを使ってWeb Workerを呼び出します。


worker.postMessage("Execute");

view raw

index.js

hosted with ❤ by GitHub

逆にワーカー側からメッセージが来た時にはonmessageが呼ばれます。


worker.onmessage = (e) => {
alert(e.data);
};

view raw

index.js

hosted with ❤ by GitHub


このようにメインのJavaScriptファイルの中からWeb Workerを動的に作れるなら使い道があるかも知れません。なおWeb WorkerはDOM操作やwindow/documentオブジェクトへのアクセスができないので注意してください。ネットワークへのアクセスはできるので、バックグラウンドで通信を行うと言った時には良さそうです。

デモをJSFiddleにアップしてありますので参考にしてください。

ウェブ ワーカーの基本 - HTML5 Rocks

HTML5.1のフォーム入力チェック機能を試す

HTML5になって進化しきった訳でも、進化しなくなる訳でもありません。新しい仕様がさらに進められています。それらはHTML5.1として策定されています。

今回はそのHTML5.1の中の入力チェック機能、HTMLInputElement.reportValidityについて紹介します。

HTMLInputElement.reportValidityとは?

仕様はHTMLFormElement.reportValidity() – Web APIs | MDNにまとめられています。まだ実装されているブラウザはGoogle ChromeやFirefoxくらいになります。HTML5で新しく追加された入力属性を使って入力値の検証を行えるAPIになります。

主な入力チェック

よく使われるものとしては以下があります。

必須チェック

required 属性で指定します。


<input name="name" type="text" required />

view raw

index.html

hosted with ❤ by GitHub

パターン

正規表現を使って入力パターンを指定します。この場合、title属性も使ってエラー時のメッセージを指定するのが良いようです。以下はごく簡単な電話番号チェック(国際電話には対応していません)です。


<input name="tel" type="tel" id="tel" pattern="[0-9]{2,4}-[0-9]{3,4}-[0-9]{4}" />

view raw

index.html

hosted with ❤ by GitHub

確認入力

メールアドレスやパスワードなど、確認入力を行う場合のチェックは以下のように実装します。まずHTMLにはメールアドレス入力欄が二つあったとします。


<div class="form-group">
<label for="exampleName">メールアドレス</label>
<input name="email" type="email" id="email_addr" required />
<small id="emailHelp" class="form-text text-muted">必須</small>
</div>
<div class="form-group">
<label for="exampleName">メールアドレス(確認)</label>
<input name="email_addr_repeat" type="email" id="email_addr_repeat" required />
<small id="emailHelp" class="form-text text-muted">確認入力</small>
</div>

view raw

index.html

hosted with ❤ by GitHub

そして確認入力のメールアドレスに対する入力イベントを使って検証を行います。エラーになる場合は該当要素の setCustomValidity メソッドに対してメッセージを適用します。


var mail = document.getElementById("email_addr_repeat");
mail.addEventListener("input", function() {
if (this.value != document.getElementById('email_addr').value) {
this.setCustomValidity('確認入力されたメールアドレスが異なります');
} else {
// input is valid — reset the error message
this.setCustomValidity('');
}
});

view raw

index.js

hosted with ❤ by GitHub

入力チェック

入力チェックは任意のタイミング(フォーカスが外れた時、フォーム送信時など)で可能ですが、例えばフォーム送信時であれば次のように実装します。


var elem = document.getElementById("form");
elem.addEventListener("submit", function() {
elem.reportValidity();
});

view raw

index.js

hosted with ❤ by GitHub

elem.reportValidity() が true(エラーがない)場合はフォーム送信されます。エラーがあれば送信は行われず、処理が終了します。

イベント

エラーがあった場合には該当フォームの invalid イベントが呼ばれます。


var elem = document.getElementById("form");
elem.addEventListener('invalid', function() {
// メッセージや処理など
}, false);

view raw

index.js

hosted with ❤ by GitHub


実装デモをJSFiddleにアップしてあります。実際のコード、操作について確認してください。

まだ先進的なAPIだけに、EdgeやSafariでは実装されていません。とは言え、今後サポートするブラウザが増えてくれば利用できる場面が多そうなAPIです。

HTMLFormElement.reportValidity() – Web APIs | MDN

Web上で使えるSVGエディタまとめ

SVGはHTML5になって標準化された画像フォーマットです。バイナリではなくベクターなので、拡大縮小に強いのが特徴です。しかしXMLベースなので手書きで作るのは難しく、専用のソフトウェアを使ってSVG出力するのが一般的です。

今回はそうした専用ソフトウェアを用意することなくSVGを作成できる、WebブラウザベースのSVGエディタを紹介します。

Mondrian

簡単なドロー機能を備えています。出力はPNGまたはSVGで可能です。レイヤー機能はありませんが、色や線の太さを変えるといった操作は可能です。テキストも利用できます。生成したコンテンツをWebサイトに埋め込むためのコードを出力させる機能もあります。

artursapek/mondrian: Web-based vector graphics editor

Curve App

Webベースではありませんが、Electron向けなのでHTML5/JavaScript/CSSで作られています。円や多角形、ベジュ曲線を使ったドローにも対応しています。テキストは用意されていませんが、ごく簡単なドローであれば十分でしょう。

benogle/curve-app: Vector drawing desktop application

SVG-Floorplan-Editor

HTML5製のフロアマップエディタです。ドアを追加したり、壁を描けるようになっています。フロアマップに特化しているので会社の図面を作ったりするのが簡単です。

oodavid/SVG-Floorplan-Editor: Simple SVG Floorplan Editor for a client

jsvectoreditor

本格的に使えるSVGエディタです。直線、四角、円、曲線、文字、画像、連続線、テキストなどが用意されています。もちろん配置したオブジェクトの移動や回転もできます。保存機能はなく、XML(SVG)が表示されます。これをコピーしておけばまた再現も可能です。

Google Code Archive – Long-term storage for Google Code Project Hosting.

SVG-edit

ツールバーの並びなどがローカルアプリケーション風になっており、使い勝手の良いSVGエディタです。文字や円、四角、直線、ベジュ曲線、自由線が描けます。描画後、オブジェクトの移動や色の変更などもサポートされています。レイヤーにも対応しています。

SVG-Edit/svgedit: Powerful SVG-Editor on your browser


Webブラウザベースなので、作成したSVGがそのまま表示できると考えて良いでしょう。機能はエディタによって異なるので、目的にあったものを選ぶ必要があります。

画面の高画質化が進むのに合わせて、画像などのバイナリではサイズの肥大化が大きな問題になっています。SVGは拡大表示しても綺麗なまま、ファイルも1ファイルで済みますので今後SVGがメインフォーマットとして活用されていくのではないでしょうか。

SVGをアニメーションするライブラリまとめ

SVGはドロー系描画機能として今後、ますます高画素化の進むディスプレイに対するリソースの肥大化問題の解決策として注目が集まっていくでしょう。PNGやJPEG画像ではキャンバスサイズが大きくなるにつれてファイルサイズが肥大化しますが、SVGはベクターデータなのでファイルサイズは変わりません。

しかしSVGの魅力は静的な表示を行うだけに限りません。JavaScriptで内容を変えたり、動かしたりできます。今回はそうしたSVGアニメーションを助ける各種ライブラリを紹介します。

flubber

特定の形から別な形へ自然にモーフィングできるライブラリです。一つから一つの場合、一つから複数(またはその逆)とアニメーションが可能です。

veltman/flubber: Tools for smoother shape animations.

Shape Shifter

二つのSVGファイルを指定して、アニメーションを生成してくれるライブラリです。Web上でファイルを指定できるので、プレビューを見ながら細かく調整ができます。

Shape Shifter

zPath.js

一つのSVGファイルを描画するアニメーションを生成します。描画の方法についても数パターン用意されています。

ZetCoby/zPath.js: A jquery plugin that will animate/draw SVG

mo · js

SVGベースのモーションアニメーションを生成するライブラリです。派手なアニメーションもできますが、クリック時に光らせたり跳ねるような、ちょっとしたアニメーションも可能です。

mo · js – Motion Graphics For The Web

Primitive

指定した写真を幾何学模様で描くソフトウェアです。その描画されていく過程をSVGファイルで保存できます。

fogleman/primitive: Reproducing images with geometric primitives.

Yarrow

矢印をアニメーションで表示したり、ツールチップを表示したりします。グラフなどと連携することによって見た目にインパクトのあるプレゼンテーションが実現できます。

Yarrow — svg animated arrow pointer and tooltip

jQuery DrawSVG

jQueryのプラグインとして提供されています。SVGの内容をアニメーションしながら描画するライブラリです。

jQuery DrawSVG

Animate Plus

CSS3またはSVGでアニメーションを実現します。イージングが用意されているので、細かい動きを実装することなくアニメーションが実現できます。

bendc/animateplus: CSS and SVG animation library

SVG Morpheus

指定したアイコンが別なアイコンに変化するアニメーションを生成します。アイコンとイージング、遅延、回転などの設定だけなのですぐに使いこなせるでしょう。

alexk111/SVG-Morpheus: JavaScript library enabling SVG icons to morph from one to the other. It implements Material Design’s Delightful Details transitions. (THIS PROJECT IS NOT MAINTAINED ANYMORE)

vivus

SVGファイルを解析し、その描画をアニメーションしながら順番に行っていきます。

maxwellito/vivus: JavaScript library to make drawing animation on SVG

Walkway

基本的に一筆書きの容量で既存のSVGファイルからアニメーションを生成します。

ConnorAtherton/walkway: An easy way to animate SVG elements.

Letterbolt

SVGで文字を描くライブラリです。スクロールなどのイベントに合わせてスムーズに文字が描かれます。

buseca/letterbolt

Loading…

SVGでローディング表示を行います。ドットやラジオなど、8種類のアニメーションが用意されています。

jxnblk/loading: This could take a while

Animated SVG Icons

20種類を超えるアニメーションするSVGアイコンを提供しています。Snap.svgというライブラリを用いています。

codrops/AnimatedSVGIcons: Using SVGs on websites is becoming more and more easy with great libraries like Snap.svg. Today we want to explore what we can do with it and animate some SVG icons as a practical example.

Lazy Line Painter

一筆書きでアニメーションするライブラリです。SVGファイルは先頭と終端がなければならず、後はファイルを指定するだけでアニメーションしながら描画していきます。jQuery/Raphaëlが必要です。

camoconnell/lazy-line-painter: A jQuery plugin for path animation using the CSS –


SVGはマウスイベントなどが利用でき、形や色を変えたりできます。ユーザイベントに反応することでユーザビリティを高めたり、注目して欲しい情報を目立たせる効果が期待できるでしょう。

コールバック/Promise/Await、それぞれの実装の違いを見る

ES7ではPromise処理を簡素化できるawait/asyncが追加されています。これによってコールバック地獄からPromiseによって抜け出せたとの同様に、Promiseによる then/catch 地獄から抜け出せるようになります。

サンプルコード

例えば処理を2秒間遅らせて、その結果を取得すると言った処理を考えてみます。ES5で書くと次のようになるでしょう。


function delay(x, f) {
setTimeout(function() {
f(x);
}, 2000);
}
function main() {
delay(10, function(x) {
console.log(x);
});
}
main();

view raw

index.js

hosted with ❤ by GitHub

さらにdelayを2回呼び出すと次のようになります。ネストが一つ深くなります。


function delay(x, f) {
setTimeout(function() {
f(x);
}, 2000);
}
function main() {
delay(10, function(x) {
console.log(x);
delay(20, function(y) {
console.log(y);
});
});
}
main();

view raw

index.js

hosted with ❤ by GitHub

Promiseの場合

Promiseを使った場合は次のようになります。ネストが深くならず、thenを使ったメソッドチェーンが可能になります。


function delay(x, f) {
return new Promise(function(res) {
setTimeout(function() {
res(x);
}, 2000);
});
}
function main() {
delay(10)
.then(function(x) {
console.log(x);
return delay(20);
})
.then(function(y) {
console.log(y);
});
}
main();

view raw

index.js

hosted with ❤ by GitHub

awaitを使った場合

さらにawaitを使った場合です。ネストが一段減りますが、処理を行う関数を async で囲む必要があるので、最低一つの関数の中で処理する必要があります。Promiseだけの場合は必ずしもmain関数は必要ではありません。


function delay(x) {
return new Promise(res => {
setTimeout(() => {
res(x);
}, 2000);
});
}
async function main() {
var x = await delay(10);
console.log(x);
var y = await delay(20);
console.log(y);
}
main();

view raw

index.js

hosted with ❤ by GitHub

awaitのコードをES5に変換する

ではこのawaitのコードをBabelを使ってES2015のコードに変換した場合、どのようなコードになるのでしょうか。以下のコードはそのままnodeで動くわけではありませんが、次のようなコードが生成されます。

await的な機能を実現するために while ループを続けているのが分かります。ちなみにこれは delay を一回しか使っていない場合です。


"use strict";
var main = function () {
var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
var x;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return delay(10);
case 2:
x = _context.sent;
console.log(x);
case 4:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
return function main() {
return _ref.apply(this, arguments);
};
}();
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
function delay(x) {
return new Promise(function (res) {
setTimeout(function () {
res(x);
}, 2000);
});
}
main();

view raw

index.js

hosted with ❤ by GitHub

delay を2回実行すると次のようになります。 context.next/context.prevを使ってステータスを管理することで、ネストが深くなるのを防いでいます。ですが、switchで使っている数字は非同期処理が追加されるごとに数字が増えていきます。Babelの生成したコードを読み取るのは大変になっていくことでしょう。


"use strict";
var main = function () {
var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
var x;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return delay(10);
case 2:
x = _context.sent;
console.log(x);
_context.next = 6;
return delay(20);
case 6:
x = _context.sent;
console.log(y);
case 8:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
return function main() {
return _ref.apply(this, arguments);
};
}();
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
function delay(x) {
return new Promise(function (res) {
setTimeout(function () {
res(x);
}, 2000);
});
}
main();

view raw

index.js

hosted with ❤ by GitHub

なお、Promiseの場合はrejectを使いますが、awaitを使った場合はtry/catchでエラー処理を行います。


async function main() {
var x = await delay(10);
console.log(x);
try {
var y = await delay(20);
console.log(y);
}catch(e) {
console.log('Error');
}
}

view raw

index.js

hosted with ❤ by GitHub


非同期処理はJavaScriptに付きもので、一番厄介な存在でしょう。しかしES7のawaitによってネストがなくなったり、変数を同じスコープで扱えるようになります。現在、デスクトップやスマートフォンのほとんどのブラウザでサポートされていますので(IE系は未サポート)、HTML5を活用する際にはぜひ使ってみてください。