ブラウザ再起動時にイベントハンドラが発火する問題の対策

JavaScriptのプログラムを作成していてハマってしまったことについての話です。

それが何かというと、ブラウザのonchangeの挙動です。普通に使っていると別段の不満もなく使えると思うのですが、僕はちょっと違う使い方をしていたのでそれについて話していこうと思います。

  1. 環境
  2. どんな問題か
  3. 試したこと
  4. 解決策
  5. 終わりに

環境

Google Chrome

どんな問題か

Chromeで以下のようなinput要素の場合のonchangeの一部の挙動。一部の挙動というのは、input要素にファイルが入力されている場合にブラウザを再起動すると、onchangeハンドラが実行してしまうこと。

<input type="file" id="test">

なぜ、このようなことが起こるのかというと、再起動したときにブラウザのキャッシュが読み込まれ、ブラウザが空のinput要素にファイルを入力するためです。このため、イベントハンドラが発火してしまいます。

試したこと

  • window.onloadでinput要素の中身を消す。

    ブラウザのキャッシュ読込の方が速い。

window.onload = function () {
  // 処理
}
  • window.onbeforeunload

    反応自体はしたけどなぜか発火する。alert関数などで時間稼ぎをすればいけた。

 window.onload = function () {
   // 処理
 }

解決策

以下のサイトを参考にしました。

javascript — ブラウザの閉じるイベントを検出しようとしています

このサイトからは、先ほどのonbeforeunloadハンドラよりサイトから離れたかどうかを判定しています。

これから、このハンドラでサイトを離れる前にlocalStrageに値を入れて、発火したときにlocalStrageの値を参照して処理を止める方法を取りました。

大体以下のような感じです。

let element = document.getElementById('test');

element.addEventListener('change', () => {
    if (localStorage.getItem('onload') == 'true') {
        return;
    }
    // 処理
});
        
window.onload = function () {
    setTimeout(() => {
        localStorage.setItem('onload', false);
    }, 100);
}
        
window.onbeforeunload = () => {
    localStorage.setItem('onload', true);
}

終わりに

今回の問題に関して、かなり検索したのですが、まったくと言っていいほど情報がありませんでした。先ほど提示したサイトも、本質は少しずれている面もあるのでもしかしたら今回の問題はみんな気にしていないのかもしれません。

何にせよ、解決して気分がいいのでそのままぐっすり寝るつもりです。

おやすみなさい。