Hatena::ブログ(Diary)

0xFF RSSフィード

2011 October 24th

WEB+DB PRESS Vol.65にCoffeeScriptの記事を書きました

WEB+DB PRESS Vol.65|gihyo.jp … 技術評論社

今回は「CoffeeScriptから学ぶJavaScriptプラクティス」と題して、CoffeeScriptが生成するJavaScriptについて、どうしてこういったJavaScriptになるのかという点を中心に解説しました。

CoffeeScriptには様々なJavaScriptの(バッド)ノウハウが詰め込まれています。生成されるJavaScriptを読んでいると、「やっぱりそうなるよね」と思わせることが多くてニヤニヤしてしまいます。

そもそも、CoffeeScriptは生成されるJavaScriptの読みやすさにかなり気を使っている点が、CoffeeScriptを気に入っている一番の理由です。(その点、Dartは…)

今回も結構苦労しましたが、なかなか面白い記事に仕上がったと思うので、手にとって頂ければ幸いです。

2011 October 4th

IE8のレンダリングモードと特定文字列によるクラッシュバグ

こんにちは、だいぶ久しぶりなブログ更新です。昨日、IE8のおもしろバグを発見してしまったので、さらしものにみなさんと共有したいと思います。

早速今回のバグの再現コードをみてみましょう。

<!DOCTYPE html>ܫ<br>1日

再現ページ

たったこれだけです。JavaScriptはおろか、CSSすらありません。ただのHTMLです。これだけでIE8の標準モードのレンダリングが壊れ、強制的に互換モードにフォールバックされます。

さらに次のようにmetaタグ(もしくはレスポンスヘッダ)でX-UA-CompatibleにIE=8やIE=edgeを指定して、標準モードでのレンダリングを強制していた場合はフォールバックが働かないので真っ白なページが表示されてしまいます。

<!DOCTYPE html>
<meta http-equiv="X-UA-Compatible" content="IE=8">ܫ<br>1日
<p>IE8では真っ白なページになる

再現ページ(IE=Edge指定)

このバグはIE8(正確にはWindows XPのIE8)だけで発生しており、IE6, 7, 9などでは発生しません。IE9のIE8モードでも発生しないので、MS的には修正済みなのか、たまたま直ったのかは、よくわかりません。

ちなみに、ܫというのはWindowsではf:id:os0x:20111004181507p:imageのように表示され、f:id:os0x:20111004181508p:imageのような顔文字によく使われています。これと1日のような普通の文字の組み合わせで発生するので、実際に起こり得る組み合わせです。

今回は、このバグが発生するページと発生しないページの差分からなんとか原因を特定できましたが、正直予想し得ないバグですね。もっと追えば、より短い文字列で発生するかもしれませんし、全く別の文字列パターンでも発生するかもしれません。その辺は文字コードやWindows・IEのアレコレに詳しい方に勝手に期待しています。

2011 June 26th

AutoPatchWorkのサーバー周りのこと

地味に色々と調整しているのでまとめておきます。見よう見まねの継ぎ接ぎばかりですが…。

AutoPatchWorkはwedata(About - wedata)のAutoPagerize用SITEINFOを使わせて頂いていますが、wedataのサーバーは負荷に弱いので、SITEINFOは自前のサーバー(といっても安心のhetemlですが)に置いています。

hetemlサーバーでcronを設定して1時間に1回、SITEINFOを更新するようにしていて、AutoPatchWorkユーザーは一日に1回hetemlサーバーからSITEINFOを取得しています。

ただ、AutoPagerizeのSITEINFOは2MB近くあるので、1万人が毎日アクセスしたら転送量が20GBに達します(全員が毎日更新にくるわけではないので、実際はもっと少ないですが)。hetemlの転送量は「目安として 1日 20GB まで」(2011年6月27日時点。ちなみに以前は10GBだった)で、ChromeのAutoPatchWorkユーザーだけで6万人以上いるので余裕でアウトです(といっても、一度問い合わせてみたところ、目安を超えたら即制限がかかるようなことはないそうです)。

ただ、容量を節約するポイントは色々あって、まずオリジナルのSITEINFOは次のようなJSONデータです。

{
  "name": "Google Search",
  "resource_url": "http:\/\/wedata.net\/items\/472",
  "updated_at": "2011-04-24T23:09:52+09:00",
  "created_by": "swdyh",
  "database_resource_url": "http:\/\/wedata.net\/databases\/AutoPagerize",
  "data": {
    "pageElement": "id(\"search\")\/div[ol or div]|id(\"res\")[not(@role)]\/div[ol or div]|id(\"ofr\")",
    "url": "^https?:\/\/[^.\/]+\\.google(?:\\.[^.\/]{2,3}){1,2}\/(?:c(?:se|ustom)|search|webhp|#)",
    "nextLink": "id(\"pnnext\")|id(\"navbar navcnt nav\")\/\/td[span]\/following-sibling::td[1]\/a|id(\"nn\")\/parent::a",
    "exampleUrl": "http:\/\/www.google.com\/search?q=AutoPagerize\r\nhttp:\/\/www.google.com\/cse?cref=http%3A%2F%2Fwww.guha.com%2Fcref_cse.xml&q=firefox&sa=Search&siteurl=www.google.co.jp%2Fcse%2Fdocs%2Fcref.html\r\nhttp:\/\/www.google.co.jp\/custom?q=firefox\r\nhttp:\/\/www.google.com\/webhp?hl=en#hl=en&expIds=17259,18167,25901,25980,26440,26459,26512&sugexp=ldymls&tok=So3knfbAtc2kJy-W-lXiWw&xhr=t&q=autopagerize&cp=10&pf=p&sclient=psy&safe=off&site=webhp&aq=f&aqi=g5&aql=&oq=autopageri&gs_rfai=&pbx=1&fp=6052204b889acdd8"
  },
  "created_at": "2008-04-16T12:35:37+09:00"
}

実際に使うのはdataの中身で、さらにexampleUrlなどはデバッグ用なので、普段は使用しません。つまり、こうできます。

{
"pageElement": "id(\"search\")\/div[ol or div]|id(\"res\")[not(@role)]\/div[ol or div]|id(\"ofr\")",
"url": "^https?:\/\/[^.\/]+\\.google(?:\\.[^.\/]{2,3}){1,2}\/(?:c(?:se|ustom)|search|webhp|#)",
"nextLink": "id(\"pnnext\")|id(\"navbar navcnt nav\")\/\/td[span]\/following-sibling::td[1]\/a|id(\"nn\")\/parent::a"
}

これだけで1.9MBから715KBまで節約できます(ただ、元のデータを引けなくなるので、IDだけ追加しています)。結構節約できますが、まだ3万ユーザー程度しかカバーできません。

これにgzipを加えてみます。cronバッチの中でgzファイルを静的に作成して、.htaccessで次のように指定します。

RewriteEngine on
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.+)$ $1.gz
AddEncoding x-gzip .gz
  1. Accept-Encodingにgzipが含まれていて、
  2. リクエストされたファイル名+.gzなファイルが存在したら、
  3. URLを.gzつきに書き換え、
  4. ファイルタイプをjsonとして強制する

という指定です。

AddEncoding x-gzip .gz はレスポンスヘッダにContent-Encoging: gzipをつけて、ブラウザにgzipとして解釈させるようにしている(のだと思うのですが、あまり自信ない…)

gzip効果で、1.9MBのファイルは355KBに、715KBのファイルは152KBまで節約されます。

152KBならすくなくとも13万ユーザーまで大丈夫です。

実際、今のところ1日の転送量は8GB程度に抑えられています。

ついでにhetemlがmod_expiresにも対応していたので、ExpiresByTypeなんかも加えて、 http://ss-o.net/json/ の .htaccess はこんな感じになっています。

Options +Indexes
Header append Access-Control-Allow-Origin: *

ExpiresActive on
ExpiresByType application/json "access plus 12 hours"
ExpiresByType application/x-javascript "access plus 2 days"
<Files ~ "\.json">
  ForceType "application/json; charset=utf-8"
</Files>

RewriteEngine on
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.+)$ $1.gz
AddEncoding x-gzip .gz

IndexIgnore .htaccess *.bak *.gz
IndexOptions FancyIndexing HTMLTable NameWidth=* XHTML

2011 June 21st

WEB+DB PRESS Vol.63からJavaScriptの連載始めました

WEB+DB PRESS Vol.63|gihyo.jp … 技術評論社

id:uupaaさんの後任な感じで、JavaScript周りのホットな話題・最新情報を中心に、書いていこうと思っています。

初回は例によってデバッグ周りの話を書きました。といってもまだブログでは触れていないスマートフォンでのデバッグ方法や、 prototype.jsからjQueryに移行するたったひとつの冴えたやりかた - 0xFFでちょっとだけ触れたonerrorの具体的な使い方などを解説しています。よろしければ手にとってみてください。って発売は24日でした…紛らわしい書き方してしまってごめんなさい。。

あわせて読みたい

NoSQLデータベースファーストガイド

NoSQLデータベースファーストガイド

2011 June 17th

君は3つのリロードを知っているか?

はい、今さら聞けないウェブ開発者の基礎知識のお時間です。

ブラウザには3つの読み込みモードがあることはご存知ですか?

2つくらいはわかるけど、3つ目が出てこないって方は少なくないかもしれません。

  1. リロード
    • 一番オーソドックスなのがブラウザのリロードボタンを押したときの挙動ですね。普通ですね。
  2. スーパーリロード
    • ブラウザによっては、スーパーリロードという機能を備えています。IEの場合Ctrl+F5(Ctrl+更新ボタン)、Firefoxの場合Ctrl+F5(Shift+更新ボタン)、Chromeの場合Shift+更新ボタン(Ctrl+Shift+R)などでスーパーリロードを呼び出すことができます。スーパーですね。
  3. ページ遷移(リフレッシュ)
    • 3つ目はちょっと良い名前が思いつかないのですが、リロードではなく、通常の画面遷移での読み込みのことです。アドレスバーにフォーカスしてenterするといった方法で実現できます。むしろこれこそが普通です。

id:edvakfさん曰く、Operaにはリクエストを投げずに更新するRefresh Displayというアクションがあるらしい。確かにリフレッシュというのは適切な名前な気がする。

それぞれどう違うのか、特に1つ目と3つ目はどう違うのか不思議でしょうか?

ちゃんとリクエストの様子を眺めてみると違いがよく分かります。

リロード

f:id:os0x:20110617120324p:image

スーパーリロード

f:id:os0x:20110617120326p:image

ページ遷移

f:id:os0x:20110617120325p:image

リロードは大元のHTMLを受け取ったら、そのページ内のリソースについてレスポンスヘッダを確認しに行っています。その結果304 Not Modifiedが帰ってきて、実際にはキャッシュを使っています。

対してスーパーリロードはキャッシュに関係なく、すべてのリソースを取得しなおしています。

そしてページ遷移時は、キャッシュがあり、Expireが効いている場合はそもそもリクエストを送っていません。完全にローカルキャッシュだけを使っています。

(ちなみに、ページを進んで(ブラウザの戻る機能で)戻ったときは大元のHTMLを含めてキャッシュが使われたりします。)

なお、当然ですがすべてのブラウザがこの3つのモードを持っているわけではありません。Operaにはスーパーリロードに相当する手段がなさそう(知らないだけかもしれませんが)だったりします。

というわけで、3つのリロードの違いを意識して、開発時に使い分けるのがウェブ開発者のたしなみです。

カレンダー
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
日記の検索

最近のコメント