likes
comments
collection
share

sessionStorage会话周期,了解清楚它的边界情况

作者站长头像
站长
· 阅读数 6

sessonStorage属性是允许前端访问和存储值的一个对象,和localStorage一样使用,只是它们的生命周期有所不同,所以我要明确的了解sessionStorage的会话周期边界情况,去避免一些使用引起的bug。

1、正常的我们的理解,sessionStorage会在我们打开浏览器访问网页一直保持,刷新重新加载页面数据都会保持着,直到关闭该标签页

<html>
    <body>
        <h1>Hello, World!</h1>
        <p>This is a test page A.</p>

        <!-- 点击跳转到B -->
        <a href="B.html">Go to test page B</a>
        <script>
          console.log("Hello from test page A!");
          // 存储一个session
          sessionStorage.setItem("message", "Hello from test page A!");
        </script>
    </body>
</html>
<html>
    <body>
        <h1>Hello, World!</h1>
        <p>This is a test page B.</p>

        <script>
          console.log("Hello from test page B!");
          console.log(sessionStorage)
        </script>
    </body>
</html>

由A存储的session值,点击跳转到B后,B仍能访问到

sessionStorage会话周期,了解清楚它的边界情况

2、换一种方式,如果是使用_blank打开新标签页呢?很尴尬,访问不到值了

<html>
    <body>
        <h1>Hello, World!</h1>
        <p>This is a test page A.</p>

        <!-- 点击跳转到新标签页B -->
        <a target="_blank" href="B.html">Go to test page B</a>
        <script>
          console.log("Hello from test page A!");
          // 存储一个session
          sessionStorage.setItem("message", "Hello from test page A!");
        </script>
    </body>
</html>

sessionStorage会话周期,了解清楚它的边界情况

sessionStorage会话周期,了解清楚它的边界情况

  • 换种方式,通过js脚本window.open去打开新标签页,奇怪的发现,又可以访问到值了
<html>
    <body>
        <h1>Hello, World!</h1>
        <p>This is a test page A.</p>

        <!-- 脚本跳转 -->
        <button onclick="go()">Go to test page B</button>
        <script>
          console.log("Hello from test page A!");
          // 存储一个session
          sessionStorage.setItem("message", "Hello from test page A!");

          function go() {
            window.open('/B.html')
          }
        </script>
    </body>
</html>

sessionStorage会话周期,了解清楚它的边界情况

sessionStorage会话周期,了解清楚它的边界情况 思考为何a标签跳转打开不行呢??

网上搜索看看了,原来a标签默认rel="noopener",这种情况下不携带sessionStorage的值,需要配置rel="opener"

<html>
<body>
    <h1>Hello, World!</h1>
    <p>This is a test page A.</p>

    <!-- 点击跳转到B -->
    <a target="_blank" href="B.html" rel="opener">Go to test page B</a>
    <script>
      console.log("Hello from test page A!");
      // 存储一个session
      sessionStorage.setItem("message", "Hello from test page A!");
    </script>
</body>
</html>

3、 换种方式,直接复制A页的访问连接,新建一个标签页打开,还是很尴尬,依旧访问不到值了

4、 再换种方式,将A页再新窗口打开,这时只是指标签页的移动,值能够访问到

sessionStorage会话周期,了解清楚它的边界情况

综上情况看,我们需要注意了,会话不是在关闭浏览器前一直保留,而是标签页关闭就会销毁,有很多伙伴包括我刚开始接触前端都认为session在浏览器关闭前一直存储着,这就是边界理解错了,很可能在开发的时候写出bug,而且还需要注意新打开的标签页,通过代码打开的可以访问到,但是要注意a标签和window.open的不同,而人为打开的新标签无非共享访问

讲讲我为啥会遇到这样的误解,很早之前做后端的时候用于存储登录记录,后台有个session,记得前辈说关闭浏览器就会失效,我也就一知半解没深究,后面就与前端的sessionStorage搞混了,这两个并不是一个东西,后台存储的session有个sessionId,这个是存储在cookie中的,请求时会带着,后台根据sessionIdsession取值,判断是否登录,而通过对cookie的过期时间配置就可以达到浏览器关闭cookie销毁,从而session失效。

最后

思考我们该如何处理人为打开新标签页呢???

其实呢,比如详情页,这些打开新标签页都应该根据接口响应获取数据,而不是通过sessionStorage存储从别的地方带进详情页

不过就问题处理问题吧,前端该怎么尽量改进优化呢?我这里讲讲我的想法,通过SharedWorker来处理,新打开的标签页像原先的标签页主动获取sessionStorage值,但这样有个尴尬的点就是没有原先的标签页存在,那就没办法了,又不想使用localStorage的情况下。

// worker.js
const set = new Set()
onconnect = event => {
  const port = event.ports[0]
  set.add(port)


  // 接收信息
  port.onmessage = e => {
    // 广播信息
    set.forEach(p => {
      p.postMessage(e.data)
    })
  }
}
<html>
<body>
    <h1>Hello, World!</h1>
    <p>This is a test page A.</p>

    <!-- 点击跳转到B -->
    <a target="_blank" href="B.html">Go to test page B</a>

    <button onclick="go()">Go to test page B</button>
    <script>
      console.log("Hello from test page A!");
      // 存储一个session
      sessionStorage.setItem("message", "Hello from test page A!");

      function go() {
        window.open("/B.html")
      }

      var worker = new SharedWorker("./worker.js")
      worker.port.onmessage = function(e) {
        var result = JSON.parse(e.data);
        if (result.from === "B" && result.type === "init") {
          worker.port.postMessage(JSON.stringify({ from: "A", type: "sessionStorage", sessionStorage: sessionStorage }));
        }
      }
    </script>
</body>
</html>
<html>
<body>
    <h1>Hello, World!</h1>
    <p>This is a test page B.</p>

    <script>
      console.log("Hello from test page B!");
      console.log(sessionStorage)

      var worker = new SharedWorker("./worker.js")
      worker.port.onmessage = function(e) {
        var result = JSON.parse(e.data);
        console.log(result.sessionStorage)
        if (result.from === "A" && result.type === "sessionStorage") {
          for (var key in result.sessionStorage) {
            sessionStorage.setItem(key, result.sessionStorage[key]);
          }
        }
      }
      worker.port.postMessage(JSON.stringify({
        type: "init",
        from: "B"
      }))
    </script>
</body>
</html>