理解瀏覽器的歷史記錄

發表於2016-10-12

這是一篇基礎文章,講述一些瀏覽器裡面歷史記錄棧管理的相關內容。寫這個的起因,源於我最近想研究pushState,看看用它來實現SPA會遇到哪些問題,而pushState最終影響的就是瀏覽器歷史記錄棧裡面的內容,所以就花了點時間琢磨了一下瀏覽器是如何管理歷史記錄棧的。因為在研究的過程中,發現了一些曾經不曾注意到一些要點,所以就記錄下來了。

demo地址:http://liuyunzhuge.github.io/blog/history/demo1.html

這個demo用於進行本文後面內容涉及到的相關測試,假如你也感興趣的話,建議每次要測試一個新的問題時,都在新選項卡里面開啟這個demo,而不是從一個已經開啟過網頁的選項卡里面開啟;因為已經開啟過網頁的選項卡,它的歷史記錄棧裡面已經包含了之前訪問的網頁記錄,所以會對你要測試的問題結果產生影響。

瀏覽器會對同一個視窗(選項卡)中訪問的網頁進行記錄,不管我們是通過以下哪種方式改變網頁,瀏覽器都會把改變後的網頁記錄下來,以便通過瀏覽器的前進和後退按鈕,能夠快速的切換到已經訪問過的網頁:
1)直接在位址列輸入網頁地址;
2)通過網頁內的超連結點選,跳轉到其它網頁;但是不能是在新視窗中開啟的連結;
3)通過指令碼改變location.href跳轉到其它網頁;
4)通過表單提交跳轉到其它網頁;但是不能是提交到新視窗的表單。
總之,只要是在同一個視窗內,網頁發生了跳轉,瀏覽器都會記錄。不過重新整理除外,history物件的length屬性可以檢視當前視窗儲存的歷史記錄總數,在前面的demo頁面中,我把這個屬性列印在頁面上,只有網頁改變的時候,這個屬性才會變化;而重新整理網頁不會改變這個屬性。

瀏覽器有一個資料結構來儲存網頁的歷史記錄,我把它稱之為歷史記錄棧,因為它的結構跟棧的使用方式有些相似。

操作測試一:假如你複製前面的demo地址,然後在chrome瀏覽器下按以下步驟進行操作:

開啟新選項卡;輸入demo1.html;點選demo2.html;點選demo3.html;點選demo4.html;點選demo3.html;點選demo2.html;點選demo1.html。

瀏覽器會以下圖類似的方式來儲存以上的訪問記錄:

459873-20161010141538024-734568915

由於現在的瀏覽器都是多選項卡的模式,當你開啟一個選項卡的時候,即使沒有訪問具體網頁,瀏覽器也為這個選項卡建立好了BOM物件,比如history物件,然後把新選項卡的空白頁作為歷史記錄裡面的第一條記錄。所以在上圖中的最後一列可以看到8條記錄,跟demo頁面裡顯示的數字一樣:

459873-20161010141538977-318309560

跟歷史記錄棧一起的,瀏覽器還有一個訪問指標來表示當前網頁在歷史記錄棧中的位置。預設情況下,當我們通過前面列舉的方式改變網頁地址的時候,都會把新的頁面壓入到歷史記錄棧的頂部,同時把指標指向到這個最新的網頁,就如上面的圖中所示,每次改變了頁面,當前頁面的指標始終指向的是歷史記錄棧最頂部的那條記錄;當我們通過瀏覽器的前進後退功能(包括按鈕,快捷,右鍵選單等方式)或者是history提供的go/back/forward方法,都不會改變歷史記錄棧的內容,只會移動一下這個指標:

1)前進功能/go(1)/forward,只是讓這個指標上移1個位置;

2)後退功能/go(-1)/forward,只是讓這個指標下移1個位置;

3)go(n)讓指標上移n個位置;go(-n)讓指標下移n個位置。

瀏覽器根據移動後的指標位置,找到歷史記錄棧中的網頁進行顯示。假如接著操作測試一的結果,繼續做以下操作。

操作測試二:點選7次瀏覽器後退按鈕。

瀏覽器此時歷史記錄棧的儲存情況就變成下面這個狀態了:

459873-20161010141540727-763005808

雖然history.go(n)和history.go(-n)可以將指標移動到任意位置,但是當要移動到的位置超出了歷史記錄棧的位置範圍時,指標就不會移動。所以在操作測試二的結果中,呼叫history.go(-100)和history.go(100)都是不會起作用的。

還有兩種情況會改變歷史記錄棧的內容。

操作測試三:假如我們接著操作測試二的結果,點選三次前進按鈕,讓瀏覽器的歷史記錄棧進入到下面這個狀態:

459873-20161010141541993-1964346777

此時由於操作測試二和操作測試三都沒有改變歷史記錄棧的內容,所以正確的話,頁面上的歷史記錄統計應該還是8:

459873-20161010141543696-890984252

操作測試四:接著,我們做以下兩步操作:點選demo2.html,點選demo3.html。這個時候頁面上的歷史記錄統計變成了:

459873-20161010141544883-1747911494

history.length已經改變了,說明歷史記錄棧的內容也變化了。只不過為什麼變成6,而不是10(8+2)呢?看看此時瀏覽器歷史記錄棧的狀態:

459873-20161010184405852-2092767860

瀏覽器在往歷史記錄棧裡面壓入新的記錄時,是直接在當前指標後面壓入的,如果當前指標的後面,還有其它的記錄項,都會被丟棄掉。這樣就好理解為啥操作測試四之後的歷史記錄總數只有6個了。

瀏覽器對歷史記錄的管理還有一個要點就是對歷史記錄棧的儲存總數有限制,chrome和firefox都是50。當歷史記錄棧的儲存的量超出這個限制後,歷史記錄的儲存就會採取滾動的方式儲存,也就是新的記錄會壓入到棧的頂部,最底部的記錄會從棧的底部移除出去。通過在demo頁面裡,不斷地切換點選demo1,demo2,demo3,demo4,當達到一定次數的時候,頁面列印的統計資訊不再變化,就表示達到歷史記錄達到限制了。不過IE11,我點到100多,發現它還在變化,說明IE的限制可能更高,也可能沒有。。

本文記錄了一些瀏覽器關於歷史記錄管理的內容,可能有分析不到位的地方,歡迎大家的批評與指正。以上內容希望對有需要的朋友加深對history以及pushState的理解有所幫助,謝謝閱讀:)


補充於2016-10-12:

網頁錨點的變化,也會導致歷史記錄棧的更新,特性與前文描述相同。

相關文章