Nicholas C. Zakas「ローディング系jsライブラリについて思うところ」
nczonline 2010.12.21のエントリ
Thoughts on script loaders
- ローディング系jsライブラリはいらない派のNicholasが使われてるテクニックを切り口に見解を淡々を述べる趣旨のエントリ
- いらない派であること、他の人のエントリの紹介とかが不正確、ということでコメント欄が盛り上がってる
以下斜め読んだ内容
最近のjs高速化ニュースとして・・・
- ControlJS
- 2010.12.14スタート
- クリエータはSteve Souders
- ゴールは、jsのロードと実行タイミングを簡単にコントロールできるライブラリ
- メリットは、jsの並列ローディング(によるページ高速化)
- jsのロード/jsの実行の分離
- jsのロード完了してもjsの実行は遅延、とかやること
- ControlJSはStoyan Stefanovのアプローチを採用
- (補足1)object/image要素経由だとjsはロードされる(キャッシュされる)が評価・実行されないことを利用したテクニック
- (補足2)前に斜め読んだ。Stoyan Stefanov「CSS/JSを先読しつつJSは実行させないでおく」 - クライアント・サイド・スクリプティング with Web Standards
- ControlJSの使いどころ
- Steveがシリーズもののエントリ3つ書いてるから読め
- ControlJS part 1: async loading
- このエントリコメント欄でKyle Simpson(LABjsクリエータ)がControlJSの批判を展開してる
- ControlJS part 2: delayed execution
- ControlJS part 3: overriding document.write
- LABjs
- ControlJSのライバル。2009年にスタートしたライブラリ
- クリエータは、Kyle Simpson
- LABjsのゴールはControlJSのゴールと少し違う
- LABjsのゴール1
- jsファイルの並列ローディング。これはControlJSと共通
- LABjsのゴール2
- jsファイルの実行順番のコントロール。これはControlJSにはない機能
- jsの並列ローディングのブラウザのサポート
- サポートされていたりいなかったり
- サポートされてないブラウザでも並列ローディングができるようにするテクニックはある
- たとえばLABjsが提供してる
- ControlJSもLABjsもそれぞれ異なるブラウザ判別テクニックを使ってる
- 各ブラウザごとに並列ローディングを最適化するために必要
- LABjsはFeature Detection(サポートしてるオブジェクトで判別)プラス、いろいろ仮定して判別
- シンプルなFeature Detectionじゃないのでinference detectionととりあえず呼んでる。
- Fx判定用にFx3系独自の「__count__」プロパティをチェックして判定してた
- Fx4(というかjavascript1.85)では「__count__」廃止。このテクニックは死亡
- Kyleは「__count__」廃止を把握済
- (補足)LABjsはすでにこの問題を克服済み。
- ControlJSはUA Detection(UA情報見て判別)使ってる
- Feature Detectionはアプローチとして問題があるし、UA Detectionよりも高精度というわけでもない
- この問題については詳細にエントリ書いた
- 好みになるが自分(=Nicolas)はUA Detection派
- 「何をしてるのか」が明示的なテクニックの方がエラーが発生したときにデバッグがより早くできると思うから
- 歯切れ悪いが一応。UA Detectionの方がFeature Detectionよりも優れてるという話ではない。
- 各ブラウザごとに並列ローディングを最適化するというアプローチがはまり込む問題
- ControlJSも明日は我が身。今のところ無事だが
LABjs/ControlJSなどローダー系ライブラリがページ高速化のために取り組んでる問題
- 大まかにいうと3つ
- 1.jsファイルの並列ローディング
- 2.jsファイルの実行順序のコントロール
- 3.jsファイルローディングと評価・実行を分離
- 1.jsファイルの並列ローディング
- ライブラリによる実装のメリットは大きい
- ブラウザでjsファイルのローディングがサポートされつつある
- Steveがエントリ書いて指摘してる
- Loading Scripts Without Blocking
- (補足)この紹介は結構ミスリード
- Steveのエントリはjs/css/img/html等のページのすべてのリソースの問題の並列ローディングの実現がテーマ
- 最近のブラウザの並列ローディングは向上した点は指摘
- けど、html(iframe要素経由)や画像(img要素経由)ではブロックされてることを指摘してる
- Steveの記事は前に斜め読んだ(S.Souders「Loading Scripts Without Blocking」 )
- 旧世代ブラウザで速度を絞り出すチューニングはパズルとしては面白い
- jsライブラリが取り組む問題ではない
- ブラウザが取り組み・サポートしつつある
- 2.jsファイルの実行順序のコントロール
- LABjsが注力してる
- ControlJSはサポートしてない(する気がない)
- ロードされた複数のjsの実行順番を決める
- 個人的にはこの機能はおすすめしない
- この機能を必要としてるエンジニアがいるのは事実
- 3.jsファイルのローディングと評価・実行の分離
- いつでも好きなタイミングでjsが実行できるようにする
- できるだけ高速でjsローディングしたい。けど評価・実行は好きなタイミングでできるようにする
- jsコミュニティ内部でもさんざん実験・検証がされてきた機能
- Steveがエントリでも指摘してる
- ControlJSが注力してる
- LABjsはサポートしてない
- (補足)不正確な紹介
- LABjsもこの機能はNicholasが口述する「不正なmimeタイプを使うテクニック」を使ってサポート
- progressive enhancementに則ったjsの実装のかたち
- ブラウザも全然サポートされる気配がない
- ローディング系jsライブラリの活況は開発者がパフォーマンス向上に取り組む姿勢のあり方を示してる
- ローディング系jsライブラリを使うことはお勧めできない
- ローディング系jsライブラリが解決しようとしてる問題群はブラウザレベルでサポート・解決されるべき代物
- ローディング系jsライブラリの取り組む問題と解決にKyleがクソ長いエントリ書いてる
- 仕事が忙しいので逐一リプライする余裕がない
script[async]のスペックにKyleが修正案を出してる件
<script async src="foo.js"></script> <script async="true" src="foo.js"></script> <script async="false" src="foo.js"></script>
- html5のasync属性
- Kyleの修正案
- オンザフライで生成したscript要素のasyncプロパティに値を設定するとモードが変わる
- (コメント受けて追記)
- Kyleの努力はすごいと思う
- "async=false"という字面からイメージされる内容と実際の挙動が違うのがわかりにくい
- 字面からだとscript[async=false]は「このjsファイルの非同期ローディングはキャンセルする」
- 実際の挙動は「このjsは非同期ローディング。かつ実行順序は保存します」。
- コードが読みにくいと感じる。自分は明示的なものが好きなため。
- (補足)Kyleの提案はHTML5のスペックに採用
-
- Bug 11295 – Make script-inserted external scripts that have .async=false execute in the insertion order, default to true
- 「async=false」指定するとオンザフライで挿入された順番でjsが実行されるという仕様になった
-
Kyleがscriptgroup要素を提案してる件
<scriptGroup id="group1" ordered="true"> <script src="foo.js"></script> <script src="bar.js"></script> <script> somethingInline(); </script> </scriptGroup>
- 複数のjsファイルのグループ化と順序付けをできる
- 明示的なので自分はこの提案は好き
- scriptgroupにハンドラーをセットすれば、ラップされたjsファイルのローディングが全部完了したタイミングを通知できる
- 要素が増えるという負担はある。最終的にはこの提案の可否は開発者が支持するかどうか次第
再びjsファイルのローディングと評価・実行の分離
- この機能自体は今後ますます重要
- 以前の自分の講演で、ページロード後のjsの動作のせいでサイトのユーザの取りこぼしがある点について話をした
- 実装した機能のエッセンスは簡単
- jsのダウンロードをリクエスト
- ロードしたファイルをキャッシュへ保存
- 後からjsのコードを実行するためメソッドを呼び出す
Kyleはwikiページ作って要望リストをまとめている
//実装例の骨格だけ //script要素生成し //偽のmeme-type"text/cache"をセットしてDL完了後即評価・実行されないようにする var script = document.createElement("script"); script.type = "text/cache"; script.src = "foo.js"; //jsのローディング完了をチェックし //DOMツリーに挿入 script.onload = function(){ //script has been loaded but not executed }; document.body.insertBefore(script, document.body.firstChild); //あとからロード済みjsを実行 //メソッドは別に定義。正しいmemetypeをもつscript要素作ってDOMツリーに追加 script.execute();
jsローディングライブラリが色々ある状況
- SteveやKyleのような優れた開発者が取り組んでる
- LABjsやControlJSなどいろいろ選択肢のある状況はいいこと
- 個人としてはこの手のローディングライブラリの使用は勧めない
- 懸念点として、ブラウザのアップデートをチェックしてメンテしないといけなくなる
- 新バージョンリリースで挙動がおかしくなってないかチェックしないといけなくなる
- チェックするコストがかかるがこれは削れるコスト
コメント欄
- Steve Souders
- ローディング系jsライブラリの賞味期限は短いが期限切れではない
- ブラウザがこの手のライブラリの機能をサポートしてくれるのが一番よい
- ブラウザがサポートすればこれらライブラリは不要になる
- HTML5のスペックもブラウザも現時点でこれら機能を提供してない
- ブラウザがこの手のライブラリの機能をサポートしてくれるのが一番よい
- 「jsファイルローディングと評価・実行を分離」機能
- IEだと「jsファイルローディングと評価・実行を分離」の実装は非常に簡単
- script要素をオンザフライ生成後DOMツリーへの追加をストップ。これだけでJSの実行を遅延できる
- Fx3.6〜で導入されたlink[rel="prefetch"]のような形でネイティブサポートされていくと予想
- IEだと「jsファイルローディングと評価・実行を分離」の実装は非常に簡単
- ローディング系jsライブラリの賞味期限は短いが期限切れではない
- リプライ(Nicholas)
- IEのサポートは知らんかった。
- Kyle Simpson
- 色々物申す
- 並列ローディングが解決するべき問題を狭く捉えてる
- Nicholasはjsとjsの並列ローディングだけを見ている
- 並列ローディングは2つの仕事がある
- jsと他のリソース(js/css/img/html)の並列ローディング
- DOMContedLoadedイベントの発火の遅延などの副作用ゼロで並列ローディングを実現
- Nicholasはjsとjsの並列ローディングだけに焦点あててるが、ローディング系jsライブラリの把握として不正確
- Nicholasはjsとjsの並列ローディングだけを見ている
- LABjsが「jsファイルの実行順序のコントロール」に注力という紹介も不正確
- ローディング完了したjsから即実行。これがLABjsのデフォルト
- .wait()メソッドを使うとオプションで実行順序を設定できる
- 実行順序の指定が必要な場面は現実によくある。望ましい現実化どうかはさておき。
- script[async="false"]は事実確認が不正確。async="false"、async="true"は挙動に違いある。Fx/WebKitで実装済
- scriptgroup要素は今の所script[async]ほど反響がない
- 「jsファイルローディングと評価・実行を分離」をIEがすでに実装済みの件
- IEのサポートは、ロード済jsファイルがキャッシュされてるかどうかのチェックとかuglyな部分がないのがnice
- この機能は仕様にも盛り込まれてる。IE以外のブラウザがまだサポートしてない
- feature inferenceは現状で一番優秀
- Nicholasのと意見が違うのは認めるが、LABjsで使ってるこのテクニックはうまく機能してる
- この点については他のローディング系jsライブラリの追随を許さないと自負
- リプライ(Nicholas)
- UA detection v.s. Feature inferenceの話を出したは、LABjs批判目的じゃない。ローディング系jsライブラリの比較をするときにアンフェアなものが多いので論点を整理するために出した。エントリの趣旨からすると脱線。
- async属性の名前がよくないのは同意
- 再びKyle
- あとでかく
- async属性の紆余曲折について、Nicholas/Kyle/Henri Sivonen(@mozilla,html5パーサクリエータ)が議論してる
- あとでかく