2.5.2 history模拟历史栈

无论browserHistory、hashHistory还是memoryHistory,对于push与replace方法,其在内部实现上都模拟了浏览器的历史栈管理能力。

1.browserHistory

在代码内部,browserHistory维护了key的数组allKeys,用此数组记录历史栈的情况,其length长度与browserHistory.length的长度一致,且将key作为window.history.state的一个属性持久化存储在浏览器中。key在每次调用push方法时,都会生成一个随机值,用于唯一标识当前产生的路径,可在创建history时配置keyLength属性以控制其长度。push方法模拟了浏览器的历史栈管理能力:

allKeys作为一个内部维护的数组,其记录了历史栈中栈记录的身份标识。其中key的生成如下:

与replaceState行为一致,在调用replace时也会替换对应栈记录位置的key:

keyLength使用频率较低,预计将在history v5.x之后的版本中移除。

如图2-3所示,browserHistory虽然不能直接得知浏览器的历史栈,但可以从内存维护的allKeys数组中获得所有key的情况。

图2-3 浏览器历史栈与browserHistory中的allKeys

如从window.hisotry.state.key中获取到的值为gewr32,则可从allKeys数组中判断出当前的栈指针位于栈底。由于在内存中维护了栈记录,在导航时能获得更加全面的信息;也可以阻止导航,这将在2.5.5节介绍。

2.hashHistory

hashHistory没有持久化能力,其使用当前路径URL作为路径的唯一标识,而不是随机生成的key,其维护的历史栈数组为path数组allPaths。allPaths的功能等同于allKeys:

hashHistory维护的历史栈数组allPaths同样会在调用history.block时发挥作用。

3.memoryHistory

与browserHistory、hashHistory不同的是,memoryHistory没有外界的副作用。由于memoryHistory模仿了浏览器的管理能力,其内部自身应维护一个历史栈以便history.go(-1)等方法能正常运行。与browserHistory、hashHistory不同,memoryHistory维护历史栈的目的是提供类似浏览器对历史栈的管理,而不是作为history.block的参考历史栈。而且,memoryHistory可通过history.entries接口获取整个历史栈信息,这是browserHistory与hashHistory不具备的。