ジンジャー研究室

長めのつぶやき。難しいことは書きません。

HTTP/2で再帰的にPUSH_PROMISEする場合の注意点

タイトルの通りで、今ぶち当たっている問題を共有するのが目的。

f:id:jinjor:20150311140752p:plain:w400

図のように、あるHTMLを起点にして依存しているすべてのリソースに対して、再帰的にPUSH_PROMISEしたい。

PUSH_PROMISEはPROMISEであるため、サブリソース本体が起点となるリソースよりも早く返却される必要はない。つまり、ブラウザはサブリソースの返却にブロックされずに、先に目的のリソースの評価を開始できるというメリットがある。

f:id:jinjor:20150227224512p:plain:w400

再帰的なPUSH_PROMISEとは

ただし、これを再帰的にやろうとした場合に問題が生じる。 実は、PUSH_PROMISEはクライアントからのリクエストにあたるストリームからしか発行できない。 だから、Stream 2からStream 4を生み出すのは無理。

f:id:jinjor:20150311143601p:plain:w500

そうすると、Stream 1からPUSH_PROMISEを発行しなければならないのだが、この時にStream 1が既に閉じられているとエラーになる。

f:id:jinjor:20150311143606p:plain:w430

つまり、依存するすべてのリソースに対してPUSH_PROMISEするまで、Stream 1を閉じてはいけないことになる。 Stream 1を閉じずにindex.htmlを送ることもできるが、そうするとPUSH_PROMISEされる予定のリソースを先にリクエストして干渉する恐れがあるので避けたい(SHOULD)。

そもそもの動機

これがいつ問題になるかというと、動的にHTMLなりCSSなりをパースしてPUSH_PROMISEしたい場合、パース中は最初のストリームが返却待ちになってしまう。依存ツリーがが深ければ深いほど待ち時間は長い。

かといって、事前に静的に依存関係を調べる方法だと、そのタイミングとキャッシュの管理を考える必要が出てくる。

まとめると、

  • 動的に依存を調べる場合はリクエストの返却が遅れる(PROMISEの恩恵が受けられない)。
  • 静的に依存を調べる場合はキャッシュの管理などが必須。

こんな感じなので注意が必要。もう仕様もFIXしちゃったし…。

そしてこのエントリは、最初の図のように出来ると思って色々作り始めてしまった愚痴でもある。