Experts.jp日本に、もっとエキスパートを。web?」についてのレポート前編です。Sync等を使い、NativeアプリのようなUXを提供するWebアプリを指す言葉です。Chris氏いわく、23年間Webをやってきているけど、やっと理想だと思っていた世界、ユーザーとのエンゲージ率が高いUXを持つサイトがWebというPlatformのみで制作することが可能になっている。Edgeな話をします。リリースされていない機能だったりCross-Browser、Cross-Deviceで動かない機能、Experimentalフラグの変更を必要とする機能も含まれます。ここではカバーしない機能もあり、その代表的なものの一覧はこちらです。Edge)開発をより簡単に速くするための機能(導入済み)Promise非同期のAPIの記述を一貫性のあるパターンで書く方法です。Callbackのように混乱しやすかったり、散らかりやすくなく、同期APIをブロックすることもなくなります。Web開発はブロッキングをなくすようなデザインをするように考え方を変える必要があります。Promiseは新たなWebのAPIをデザインするときには一般的な方法になっていて、以下はPromiseを使うAPIとしてデザインされている代表的なものです。MIDI[実装状況]FetchFetchもPromiseを使っています。FetchはXMLHTTPRequest(XHR)と似ていてNetworkリクエストを行います。XHRとの違いはPromiseを使って可読性が上がっているところ。Fetchで何をしているか分からなくても、見たら何となく内容を理解できるところです。Callback地獄からの脱却、XHRの複雑な部分から開放してくれる。JSONや他のデータ・タイプを扱うことも可能です。左がFetch、右がXHR。見、XHRとも悪くないけど、Stateのチェックとかしてないから悪くないのであって、本来はもっと長くゴチャゴチャするのでご注意してください。ES6のアロー・ファンクションを使うと、さらにこんなにもキレイになります。問題はこのままだとデータを完全に取得してからでないとJSONとしてParseができないところ。Atomicで割り込みができない。そこで実装中なのが、このFetchやその他のAPIの本当の能力を引き出す機能、それがStreamです。[実装状況]StreamStreamは基本的な要素で、その使い道はいろいろあると思います。Jakeはこんなことを言ってます。「Streamは2016年の大きな1つの機能になるだろう」と。StreamはProgressiveなデータ転送を可能にするからです。全てのデータを受け取っていない状態でも、受け取った順に処理することができる。Progressiveなレンダリングだったり処理が可能になるのです。Shellアーキテクチャを使う場合等は1度に複数の場所からデータを取得するので、とても重要な要素になります。画像は左側の「Fetch」の全てが終わらないと真ん中の「Process」に進めない、それに引きづられて最終的な「Render」も遅くなってしまう、を表した図。Wikipediaのサイトで、Streamを使うとどれくらい差がでるかを比較したデモ動画です。(画像が小さくてすみません。Streamの真ん中の2つよりも速い。この理由は、真ん中の2つは全てのデータを取得するのを待ち、それから処理を始め、その後最終的にレンダリングされるからです。ハイパフォーマンスなProgressiveなWebアプリなサイトであるのに、表示が遅くては致命的とも言えるでしょう。Shellアーキテクチャのがコストが高い(時間がかかる)場合もあります。[実装状況]さらにパフォーマンスをテーマに話を続けます。ハイパフォーマンスなWebサイトを作るために実装しているエキサイティングなその他の機能を紹介します。RequestIdleCallback多くのWebアプリ、サイト上では多くのスクリプトが動いていることと思います。全てのスクリプトがユーザーが見ている画面に直接関係のあるスクリプトではなかったりしますよね。Analyticsデータの送信です。スクロール中に動いてしまうとスクロールがロックしたりユーザー体験(UX)の質は下がります。そこで、そういったユーザーが見ている画面に直接影響を及ぼさない処理を空いている時間に走らせよう、という機能がRequestIdleCallbackです。RequestAnimationFrameはできるだけ60fpsで表示ができるようその処理をスケジュールしています。RequestIdleCallbackはRequestAnimationFrameと一緒に動作しています。レンダリングに関係しない処理を、レンダリング処理が空いているところにスケジュールしてくれる、という動きです。実装は難しくないけど、ここで動かしたいタスク(処理)の1つ1つはリーズナブルな時間で終わるように分割されている必要があります。Workerで動作させることをおすすめします。ちなみにNetflex、Facebookはこの機能を既に導入しています。51でShipされます(I/O後の2026年5月下旬にリリースされました)が、ユーザーによりよいスクロール機能を提供するための機能です。スムーズなスクロールの機能はWebにとって、特にタッチデバイスでのWebにとってはとても重要です。モダンなブラウザは高コストなJavaScriptがUIスレッドで走っていたとしても、スクロールを別スレッドでハンドリングする機能を持っています。問題はそれがタッチやスクロールeventハンドラを持っていると、最適化で負けてしまうところです。それらのハンドラは.preventDefaultをCallすることでスクロールを完全にブロックしてしまうからです。eventハンドリング中に.preventDefaultがCallされるかどうかは分からないので、高コストなJavaScriptの処理が完了するまで待つ必要が出てきてしまうのです。そこでPassiveEventListenerでは、.preventDefaultをCallしないと宣言し、スクロールがeventによってブロックされないようにするのです。Androidではその80%のTouchEventがブロックされる必要はないのにブロックされている。その10%がスクロール開始までに最低100ms待ち時間が生じた。その1%は500msの待ち時間がスクロール開始までに生じている。CNNのサイトで導入したのと、していないのとで比較をしてみます。(ビデオはこちらから:preventdefaultをcallしてないのに遅くなっているのとPassiveEventListenerを使った場合の比較ビデオ)この違いを生むための実装は、たったこれだけです。Elementが画面内に入っているかどうかを見る、またその場所も簡単に得ることができるのがこのAPI。今までも実装は可能だったけど、効率的ではなかったし問題もいろいろあった。Observerのコードを見てみましょう。画面内に入ったかを監視したいターゲットとなるElementを決めましょう。IntersectionObserverのオブジェクトの生成時します。生成時には画面内に入った場合の動作についてのCallbackも渡します。最後に生成したオブジェクトでどのElementを監視するかを指定します。51以降で御覧ください)デモページはとてもスムーズで超速な無限のスクロールを提供しています。Workerを使ってキャッシュすると解決します。たくさんの画像を表示するページ等には持ってこいですね。50でShip済みで、リソースのPreload(事前読み込み)を行います。rel=”prefetch”>とは違い、現在のページ内のリソースを読み込む優先順位を指定ができる属性です。HintsHTTPヘッダにつけることで取得するコンテンツの種類を事前ネゴシエーションすることができる。ネゴシエーションの要求を出すことで、ユーザーのデバイス、環境によってサーバ側が提供されるコンテンツを差替えてServeすることが可能です。サーバ側に実装されるものであって、クライアント側のコードで指定するものではありませんが、以下の様な要求ができるように用意されています。50でShip済みで、クライアント側でCanvasをそのままBlobにすることができます。一説によるとこの機能が実現するまでに6年かかったそうです。.toDataURL()から得られるBase64の文字列を操作することなく、画像としてそのままサーバにアップロードしたり、IndexDBに保存したりできるので、より簡単に再利用することが可能になります。[実装状況]ImageBitmapChrome50でShip済みで、ImageBlobを他のCanvasにそのまま描くことも可能になっています。Canvasに描くために画像をデコードするのはとても一般的ですが、画像のデコードにCPUリソースをとても多く使ってしまうという問題点があります。Base64とデータの間での処理をすることなく扱えるようになったのです。することで、例えば他の画像、エレメント、ビデオ等をCanvasに描くときと同じように扱えるようになりました。PipelineクライアントではなくてChrome自体のコードの話です。デスクトップ版でもモバイル版でも全く同じ処理がされるようなMediaようにPipelineを持つようにしました。Stackでの処理は行わないようにしました。これによりCross-Platformでも一貫した処理(例えばキャッシュ、エンコード、デコード)を行うようになっています。よって、Cross-Platformでのデバッグをより簡単にしています。MediaRecorderビデオ、オーディオをキャプチャするだけでなく、エンコードして保存をすることが可能になりました。取得したオーディオをMP3にクライアント側で変換してサーバにアップロードすることが可能です。49以降でご覧ください)コードはこんな感じです。MediaRecorderのオブジェクトをOptionを渡して作成して、データを取得したときのCallbackを.ondataavailableに指定します。Callbackにはどう扱うかを書くのだけど、ほとんどの場合取得したデータ(Blob)をくっつけるだけです。最後にどれだけの長さの動画を作るかを指定して完了です。サーバにアップロードする、ローカルに保存する等ができるようになります。Audioでの質問として何度か受けていますが、まさにこれがその解です。Area)、ロック画面にMedia操作用のUIを出すことができるAPI。Mediaに関するアプリを作っている開発者であれば一度見てもらいたい。49でShipされています。同じ属性を何度も繰り返し書くことの削減してくれたり、また色・見た目等のテーマの変更にもとても有効です。ContainmentCSSを隔離してパフォーマンスを最適化してくれる機能です。Partyのウィジットを使った場合、そのウィジットのCSSを隔離することで自サイトのパフォーマンスに影響が出ないように最適化してくれます。48でShipされたばかりです。Faceのチェック、またそれらのダウンロード状況を確認できるようになりました。これによりFontが実際にどれくらいダウンロードされたか、どんなFontであるかを知ることができるようになりました。[実装状況]Progressiveに速いスピードで短い説明で新しい機能を紹介しまくって、後で調べてね、と言っている感があるように聞こえるかもしれないですので、少し休憩というようなお話をしますね。(後編の予告など)ということで、この辺りで前編は終了です。Bluetoothについてお伝えします。Bluetoothの説明中の一幕。