本文为HTML标准解读系列文章,其他文章详见这里。
以下的这几个web API,虽然他们的功能各异,但是底层却有同样的机制,你知道什么吗?
history.pushState()
/history.replaceState()
:修改浏览器的历史堆栈。window.postMessage()
:实现文档之间的跨域通信。- Channel通信API:使用频道进行通信。
- Channel广播API:同时给同一浏览器下多个同源的文档广播消息。
worker.postMessage()
:worker api,不同线程直接的交流,
没错,答案就是:结构化克隆(structured cloning)。
什么是结构化克隆?
一般来说,当一个页面unload
的时候,该页面内所有由JS创建的对象都会被垃圾回收。但有时候我们需要保留一些页面的状态,比如页面内动画的帧数,这样当用户返回的时候,动画能够接着上一次跳转出去时的地方开始播放,而不用从头开始。这也是history.replaceState()
的重要使用场景之一。
当你调用history.replaceState(state, null)
的时候,state
对象能够被浏览器缓存下来。待你之后通过历史导航按钮返回该页面时,你又能够在history.state
上重新拿到state
这个数据了。这是怎么做到的呢?
你的直觉可能已经告诉你答案了,就是使用序列化。如果你对「序列化」的概念不熟悉,其实JavaScript语言里就有一套JSON
的序列化机制。我们用JSON.stringify()
将js对象转化为便于存储、分发的json字符串,这个过程叫「序列化」;我们用JSON.parse()
将json字符串解析为js对象,这个过程叫「反序列化」。
而HTML也有一套自己序列化机制。与JSON.stringify()
不同的是,这套机制对于不同类型的js对象定义了不同「序列化」以及「反序列化」的算法/步骤,有的对象在序列化的过程只会保留一部分的属性,比如正则表达式lastIndex
属性的值会在序列化的过程中丢失;有的对象压根就不能被序列化,比如node节点
;而所有的这些算法加起来统称为结构化克隆,HTML标准的2.7小节对这套机制进行了详细的定义和阐述。
所以,简单的说,当调用history.replaceState(state, null)
的时候,浏览器会做以下的事情:
- 查看
state
的数据类型- 根据数据类型调用对应的序列化算法