Interactions with the history stack
Tags: javascript, jstrivia, html
Published: 2021-02-15 21:23:38

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


```js
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);
```

{% details Answer (click to see) %}
```js
before go 4
after go 4
after go after pushState 2
```
{% enddetails %}

-----

## Followup question!

```js
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);
```

{% details Answer (click to see) %}
```js
before go 4
after go 4
after go after replaceState 4
```
{% enddetails %}

-----

## 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:

```js
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
```

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

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

-----

## Spec talk

Here's a link to the [WHATWG HTML spec for history update steps](https://html.spec.whatwg.org/multipage/history.html#url-and-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](https://html.spec.whatwg.org/multipage/history.html#dom-history-pushstate) and here for [replaceState](https://html.spec.whatwg.org/multipage/history.html#dom-history-replacestate) - paying attention to the last words in those sentences.