Firefoxと戻るとJSONP


(2015年時点の古い記事になってしまいましたが、もったいなかったので公開します)

Firefoxで「戻る」と「戻りすぎる」という謎現象に出逢ったので、それについてのメモ。

結論から言うと、firefoxの正常な謎仕様です。setTimeoutでぶった斬りましょう。

現象

  • バナー表示を行う
  • バナーのリンクをクリックした時にJSONPでサーバと通信
  • サーバでの処理完了を待って、location.hrefに値を入れてページ遷移

という処理を行っていました。

その状況で、firefoxでだけ、遷移後に「戻る」と、バナー表示を行ったページが飛ばされて、それより前に表示されていたページに戻る...つまり、戻りすぎるという現象が発生しました。

詳しくブラウザの表示履歴を見ると、バナークリックで遷移した後、バナー表示を行ったページの履歴が残っていない状態でした。

仕様のこと

ページがloading状態の時に、location.hrefで遷移した場合、そのページを「履歴に残さない」という仕様があるようです。location.replaceの動作になるイメージですね。ただ、location.assignもこの条件ではreplaceと同様の動作になるようです。

古き悪しきlocation.hrefでのリダイレクト実装への対処を行うための仕様..のように思われますが、詳細は不明です。

Firefoxはこの仕様を妙に厳格にとるのか、2015年の今日、ver42でも発生しています。

この実証コードでは、hashbangで動作を再現できるようになっています。(fails in firefox)と書かれた項目のリンクをクリックすると#done_4になりますが、「戻る」と、#start_4になりません。

対処のこと、内部の動作のこと

実証コードのページに対処法も載っています。setTimeoutを使う方法ですね。

察するに...

JSONPの通信後、レスポンスのjsファイルから、コールバック用のメソッドが呼ばれて、レスポンス後の処理に入ります。このとき、jqueryのajaxコマンドに渡すsuccesメソッドに処理を書きますが、どうやらこれが、「jsファイルの地の文」の処理の流れから直接実行されているようです。

「jsファイル読み込み→jsファイルの地の文の実行→実行完了」までが読み込み処理とみなされるため、successメソッドで直接location.hrefを書き換えると、「読み込み処理中のページ遷移」とみなされます。

そこで、location.hrefの書き換えをsetTimeout(func, 0)の中で行うようにすると、それを呼び出した(読み込み中の)処理の流れから切り離されるので、「読み込み完了後」に遷移が発生したことになり、履歴は無事残るようになる...

ということらしい。

何故にJSONPの読み込みが、一度読み込み完了したはずのページ全体の「読み込み中」を引き起こすのかは若干納得がいきませんが...

まとめ

  • firefoxには、JSONPのコールバックでlocation.hrefを書き換えると、履歴が意図せずに消える謎仕様がある
  • JSONPのコールバック内でページ遷移を起こしたい場合は、setTimeoutを使って処理を切る

参考