DEV Community

Anthony Frehner
Anthony Frehner

Posted on • Updated on

Interactions with the history stack

JS Trivia time: given the following code, what is logged?

window.history.pushState(null, null, "/temp1");
window.history.pushState(null, null, "/temp2");
window.history.pushState(null, null, "/temp3");

console.log("before go", window.history.length);
window.history.go(-3);

console.log("after go", window.history.length);
window.history.pushState(null, null, "/temp4");

console.log("after go after pushState", window.history.length);
Enter fullscreen mode Exit fullscreen mode

Answer (click to see)
before go 4
after go 4
after go after pushState 2
Enter fullscreen mode Exit fullscreen mode


Followup question!

window.history.pushState(null, null, "/temp1");
window.history.pushState(null, null, "/temp2");
window.history.pushState(null, null, "/temp3");

console.log("before go", window.history.length);
window.history.go(-3);

console.log("after go", window.history.length);
window.history.replaceState(null, null, "/temp4");

console.log("after go after replaceState", window.history.length);
Enter fullscreen mode Exit fullscreen mode

Answer (click to see)
before go 4
after go 4
after go after replaceState 4
Enter fullscreen mode Exit fullscreen mode


What's going on?

The history stack allows you to navigate through it, and it will maintain the stack as it was through your navigation. However, when you push onto the stack, you erase any future navigations from your current location in the stack.

A simplified demonstration:

window.history.pushState(null, null, "/temp1");
// history.stack looks like ['', '/temp1']
// current entry is '/temp1'

window.history.pushState(null, null, "/temp2");
// history.stack looks like ['', '/temp1', '/temp2']
// current entry is '/temp2'

window.history.pushState(null, null, "/temp3");
// history.stack looks like ['', '/temp1', '/temp2', '/temp3']
// current entry is '/temp3'

console.log("before go", window.history.length);
// before go 4

window.history.go(-3);
// history.stack looks like ['', '/temp1', '/temp2', '/temp3']
// current entry is ''

console.log("after go", window.history.length);
// after go 4

window.history.pushState(null, null, "/temp4");
// history.stack looks like ['', '/temp4']
// current entry is '/temp4'

console.log("after go after pushState", window.history.length);
// after go after pushState 2
Enter fullscreen mode Exit fullscreen mode

and if we were only to change the pushState call above with replaceState, here's what it would look like:

window.history.replaceState(null, null, "/temp4");
// history.stack looks like ['/temp4', '/temp1', '/temp2', '/temp3']
// current entry is '/temp4'
Enter fullscreen mode Exit fullscreen mode

Spec talk

Here's a link to the WHATWG HTML spec for history update steps.

The key thing to pay attention to here is step 2:

2 If isPush is true, then:

2.1 Remove all the entries in browsingContext's session history after the current entry. If the current entry is the last entry in the session history, then no entries are removed.

isPush is true for pushState and false for replaceState, which can be found here for pushState and here for replaceState - paying attention to the last words in those sentences.

Discussion (0)