6

追踪和恢复页面访问历史

 3 years ago
source link: https://zhuanlan.zhihu.com/p/141279020
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

追踪和恢复页面访问历史

JavaScript话题下的优秀回答者

在处理页面跳转时,为了给用户提供和预期相符的页面导航(返回、前进)体验,我们需要小心地区分 push 和 replace 两种情况。一般而言,用户触发的跳转使用 push,非用户直接触发的跳转则使用 replace。

绝大多数时候这就足够保持访问历史的整洁了。但如果浏览器已经跳转到某一个页面,由于各种原因(如当前页面未保存想要取消导航、目标页面不接受导航)需要恢复到之前的状态时,又如何处理?

一想觉得那好办呀:如果是 push、forward 那就 back;如果是 replace 那就 replace 回来;如果是 back 那就 forward;总有一款适合你。然而问题就来了:

如何区分 push、replace、back 和 forward,甚至是 go(n)?

理解问题后,很多同学会想:这些问题需要解决吗?多数用户“返回”、“前进”遇到些问题通常是可以容忍的,即便不解决也少有用户会认为这是 bug。不过这不重要,重要的是我想要解决。

说到这里,就想到 YouTube 可能最近一年上的新功能,页面导航会保留最初进入时的内容推荐,避免找不到之前看到的感兴趣的推荐内容。

由于 History 对象提供的接口非常有限,主要是几个导航操作,要实现追踪我选择了自行维护一个 history stack。思路方向其实很明确,就是 history state。这里要求所有 push 和 replace 操作使用我们封装的方法,其中 push 方法会在 history state 中写入一个递增的 id。

这样一来,几次连续的 push 操作我们可以获得如下 history stack:

1 -> 2 -> 3
          ^ 当前页面

假设此时用户 go(-1),通过 popstate 事件我们可以得知当前 id 为 2,于是我们可以更新 history stack:

1 -> 2 -> 3
     ^ 当前页面

此时如果再 push,则更新 history stack 如下:

1 -> 2 -> 4
          ^ 当前页面

当然实际情况会更加复杂一些,比如当用户刷新页面后,我们就丢失了自行维护的 history stack。但好在我们依然有当前的 id,用户进行导航后我们也能获取目标 history state 的 id,只需要按照 id 顺序插入缺失的一条即可。

有了维护的 history stack 信息,我们便可以通过 push/replace/back/forward 将 history stack 恢复到几乎任何状态。

举个例子:

expected  1 -> 2 -> 3
                    ^
tracked   1 -> 4 -> 5
                    ^

在上述情况中,只需要 back 两次后 push 两次。简单概括:

  • 找到从头开始第一个不匹配的记录,并 back 到它之前(如果不是 history stack 中第一个,否则可以用 replace 处理)。
  • 参考期望的 history stack 进行 push,补全后续记录。
  • 如有需要 back 恢复光标位置。

实际上绝大多数恢复情况都是如此,除了期望的 history stack 中仅有一条,而实际 history stack 中已经超过一条情况:此时我们无法完全恢复,但可以在用户 forward 时强行 back,使实际行为相似(除了 forward 键可以点,但没有作用)。

由于前面提到的情况,自行维护的 history stack 中可能会缺少一些记录,我们需要走一步看一步,结合 popstate 的信息调整恢复路线。所以即便我们每一次都能计算出当前完整的恢复路径,也只会执行第一步。并且因为恢复过程变为了异步过程,这里需要考虑异步过程中用户触发了新导航的情况。但由于我们是逐步恢复的,考虑到新导航不会影响追踪 history stack 的正确性,所以这个问题也就轻松避开了。


有了对 history stack 近乎完全的掌控,我们便可以在更多场景更灵活地处理链接跳转提示,也可以在路由器中允许 before enter/leave 取消导航而不用担心产生错误的 history stack。

实现参考 browser-history.ts


Makeflow(makeflow.com)让团队经验可以像文档一样详细地记录在流程中,指导和验证工作实践。每一次经验的迭代都可以通过任务的执行自然“推送”到整个团队,消除工作流程从想法到实践、从实践到改进之间的多种障碍。 大到产品迭代管理,小到监控报警处置:记录、实践、再记录,把每一次进步写入团队基因——延续、变化、可复制。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK