2012年11月17日土曜日

Greasemonkeyでは広告を消去できないケースがある

とりあえず、次の環境ではそういうケースがあるようです。

  • Windows 7 home 64bit
  • Firefox 16.0.2
  • Greasemonkey 1.4

firefoxのアドオン「Greasemonkey」を使うと、ウェブページを表示した直後にユーザーの記述したjavascriptを動かすことができます。 その用途でありがちなのが「広告の非表示」です。 これは多くの場合ちゃんと動作しますが、回線次第で上手く動かないケースがあります。

動かないケースとは、「閲覧対象のhtmlファイルの転送が途中で止まった場合」です。 多くのブラウザはページを表示するとき、受信中のhtmlファイルをパースしながら、リソース(css,外部javascript,画像など)を並行してダウンロードします。 通常ですと次のような手順になるでしょう。

  1. htmlの受信受付を開始。
  2. htmlのパースを開始。
  3. パース途中でリソースが出てきたら、パースしながら並行してダウンロード。
  4. htmlの受信完了。
  5. htmlのパース完了。
  6. パースされた結果を元にレイアウト → レンダリング。並行してダウンロードしているリソースは、ダウンロード済みのもののみ表示。
  7. ダウンロードしきれていないリソースがある場合、ダウンロード済みのリソースを使って一定時間ごとに仮のレイアウトを作成する。
  8. 全リソースがダウンロードできたら、完全なレイアウトを作成して表示完了。

Greasemonkeyのユーザスクリプトが動作するのは「htmlのパース完了」のタイミングです。 通常はこのタイミングではまだレイアウトがされていないので広告の非表示スクリプトは()ちゃんと動作します。

では、htmlファイルの転送が途中で止まった場合はどうなるのでしょう? 答えは「受信済みのhtmlやリソースを元に仮の不完全なページを表示する」です。 上の手順の「htmlの受信完了」、「htmlのパース完了」の部分が先延ばしにされている状態になります。 ほとんどの人は、これのせいで表示が崩れたページを見たことがあるでしょう。

なぜこんなふうに動くのかといえば、ユーザーのストレスを軽減するためです。 例えば、テキストのギッシリ詰まった長ったらしいページがあったとして、ページの半分を受信したところでhtmlの転送が中断されたとします。 ユーザーからすれば、その半分を読んでいる間にページの残りがダウンロードされればストレスを感じなくて済むわけです。 「htmlの受信が完了しなければ絶対表示されない」となると、待たされてイライラしてしまいます。 なので、これは「ユーザーにあわせた当たり前の動作」ということになります。

しかし、前に書いたとおりGreasemonkeyのユーザスクリプトが動作するのは「htmlのパース完了」のタイミングです。 「仮の不完全なページ」が表示されるときには動作してくれません。 広告の非表示スクリプトは不発に終わります。

検索で何気なくたどり着いたページでそんな事が起こったら悔しいですよね。 しかも自前で書いたユーザスクリプトだったりしたら、もう...

残念ですが、普通のGreasemonkeyのスクリプトではどうしようも無かったりします。 ではどうすればこういうのを回避できるのか? とりあえず思いつくのは2つ。

  • 別のアドオン「Adblock Plus」を使う。
  • 自前のアドオンを作って、それで広告を消す。

Adblock Plusは広告非表示専用のアドオンという事もあって、この問題にも普通に対処してくれています。 ダウンロード停止モレ()も無さそうです。 「広告発行元のサーバに触れたくない」って場合はAdblock Plus一択で。 アドオンを入れ過ぎるとfirefoxが重くなるという問題もあるので、効果と重さとのトレードオフですね。 広告非表示以外でもGreasemonkeyを使っている人は要考慮で。

自前のアドオンってのは、まぁ、「Adblock Plusでできるんなら自前で作れなくも無いんだろう」という想像で言っています。 詳しい方法とか分からなかったり。

でもまぁ、Adblock Plusはxpiファイルの拡張子をzipにして開けば普通にコードが見れるんで、javascriptに慣れてる人なら案外簡単にできるのかも? 一応、コードを見たらnsIWebProgressListenerみたいなのが書いてあったんで「これかなぁ?」と。

私はjavascriptに慣れてないんでちょっと遠慮気味ですが、慣れてる人はやってみてください。

でもって、今更ですが、もしかしたらGreasemonkeyの深淵(入門ページ?)をのぞけば何とかなるのかも知れませんねぇ。

--------

追加 ... 次の投稿で再現例を載せておきました。

※ 広告などのリソースのダウンロードを止められるのは、htmlが短時間でダウンロードできてリソースの並列ダウンロード前にタグを消せたときのみっぽいです。 htmlのダウンロードが短時間で済んだとしても、その間に並列ダウンロードが開始されるのは止められません?