Javascriptでブラウザの閲覧履歴(history)を削除する方法+α
公開日時: 2026-04-14 11:23:28更新日時: 2026-04-14 11:25:01JavascriptでSPA(シングルページアプリケーション)を作ってると、セキュリティ関連の制約のせいで、かなり回りくどいことをやらないと目的が果たせないということがよくあります。今回の扱う「history」もその1つ。
まず、history.replaceStateでブラウザの閲覧履歴の最新のページ(≒現在のページ)のURLを書き換えたり、history.pushStateで閲覧履歴に実際はアクセスしていないページを追加したりできるんですが、このpushStateの時点で、ユーザーの操作(ボタンを押すなど)1回につき1度しか実行できないといった制約があったりします。
で、それよりももっと困る制約が、履歴の削除。
pushとreplaceがあるんだから、例えば、
history.popState();
とでも書けば閲覧履歴が削除できると嬉しいんですが、そういう関数はないんですね。
では、どうすればいいかと言うと……
解決策: history.back()を使う
単に、「URLを直前のページのものに戻す」だけなら、JS初心者でもお馴染みの「history.back」が使えます。初心者向けの入門書では「前のページに戻るボタンを作るときに使う」といった旨の解説が書かれていたりして、「前のページを読み込む」関数であると思われがちなhistory.backですが、厳密には「ブラウザの戻るボタンを押したことにする」関数なので、history.pushStateで履歴を追加した直後なら、ページ遷移は発生せず、単にURLがhistory.pushStateを実行する前の状態に戻るだけという挙動になります。
もっとも、ブラウザの戻るボタンを押したことにする以上はonpopstateイベントは発火してしまうため、onpopstateに何か処理を設定している場合は少し工夫が必要になります。
まあ、工夫とは言っても、(関数の結合度などを考えると下品ではありますが)大域変数を1つ用意して、
var on_popstate_do_nothing = false; //フラグとして機能する大域変数を用意
window.onpopstate = function () {
if (on_popstate_do_nothing) {
on_popstate_do_nothing = false;
return;
}
// ここにユーザーがブラウザの戻るボタンを押したときだけ行う処理を書く
}
on_popstate_do_nothing = true; //URLを戻す前にフラグを立てる
history.back();
と書いてやるだけで、実際にユーザーがブラウザの戻るボタンを押したときだけ目的の処理を実行するといったことは可能です。
ただし、history.backの直後にURLを読み書きすると……
ただ、上記のやり方には(大域変数を使っていること以外にも)大きな問題点があります。それは、history.backによるURLの書き換えが非同期であることを考慮していない点。
実は、history.back、JS初心者でもみんな名前を知っているシンプルな関数でありながら、内部では処理を全て非同期(≒別スレッド)で行うという曲者なんですよね。
こういうのは図にしたほうがわかりやすいでしょうか。
この図のように、history.backによるURLの書き換え処理はhistory.backを実行したタイミングではなく、それよりも少し遅れた不定なタイミングで完了するため、history.backの直後にURLを読み書きする処理を書くと、(かなりの確率で)期待とは異なる挙動になります。
//元のURLは http://example.jp/test1 だとする
history.pushState(null, "", "/test2"); //閲覧履歴を追加してURLをhttp://example.jp/test2 に変更
history.back(); //閲覧履歴を戻す
var hoge = location.href; //変数hogeの値は http://example.jp/test2 かもしれない
history.pushState(null, "", "/test3"); //これよりもあとでhistory.backの処理が完了して、このtest3の履歴のほうが削除されるかもしれない
history.backの直後にURLを読み書きするには
では、history.backの直後にURLを読み書きしたい場合はどうすればいいのかというと、Promiseを使って処理の完了を待つことが理想的な対処法になります。var history_back_promise = null; //Promiseを保持しておく大域変数
var history_back_resolve = null;
var on_popstate_do_nothing = false;
window.onpopstate = function () {
if (history_back_promise instanceof Promise) { //戻るボタンのイベントが発火した際にPromiseが宣言されていれば、これを解決する
history_back_resolve();
history_back_promise = null;
history_back_resolve = null;
}
if (on_popstate_do_nothing) {
on_popstate_do_nothing = false;
return;
}
// ここにユーザーがブラウザの戻るボタンを押したときだけ行う処理を書く
}
history_back_promise = new Promise(function (resolve, reject) { //URLを戻す前にPromiseを宣言
history_back_resolve = resolve;
on_popstate_do_nothing = true;
history.back();
});
history_back_promise.then(function () {
//ここに書いたコードはURLを戻す処理が完了したあとに実行される
});
まあ、実際のところ、わざわざ非同期処理をしているとはいっても型落ちのラズパイですら単なるURLの書き換えに秒単位の時間がかかることはあり得ないので、setTimeoutで0.1秒くらい待ってやれば処理は完了しているものと扱って問題はないのでしょう。
ただ、そういう無意味な待機時間はSEOの面で不利になる場合があるので、当ブログではPromiseを使ったやり方を推奨させていただきます……
この記事のタグ:
Javascript
Javascript