阅读视图

发现新文章,点击刷新页面。

浏览器前进后退的底层实现

一、核心数据结构:双栈模型

浏览器的历史导航通常采用两个栈(stack)来实现:

  • 后退栈(Back Stack) :保存从当前页面可以“后退”的历史页面。
  • 前进栈(Forward Stack) :保存从当前页面可以“前进”的页面,仅在用户执行“后退”后才有内容。

这种双栈结构可以很好地模拟用户的导航行为。

1.1 页面访问流程

当用户从页面 A 访问到页面 B 时:

  • 当前页面 A 被压入 后退栈
  • 前进栈被清空
  • 当前页面变为 B

状态如下:

Back Stack: [A]
Forward Stack: []
Current Page: B

1.2 后退操作

点击“后退”按钮时:

  • 当前页面 B 被压入 前进栈
  • 后退栈弹出页面 A 作为当前页面

状态更新:

Back Stack: []
Forward Stack: [B]
Current Page: A

1.3 前进操作

点击“前进”按钮时:

  • 当前页面 A 被压入 后退栈
  • 前进栈弹出页面 B 作为当前页面

状态更新:

Back Stack: [A]
Forward Stack: []
Current Page: B

二、浏览器中的 window.history 对象

浏览器提供了 window.history 对象,以编程方式访问和操作浏览历史记录。常用的方法有:

方法 功能说明
history.back() 等同于点击“后退”按钮
history.forward() 等同于点击“前进”按钮
history.go(n) 跳转到相对位置的历史记录,n 可正可负
history.pushState() 添加一条历史记录(不会刷新页面)
history.replaceState() 替换当前历史记录

这套 API 在单页应用(SPA)中尤为重要,它让开发者可以模拟浏览器的原生导航行为,同时避免页面刷新。


三、现代浏览器的内部机制

3.1 NavigationController

现代浏览器会使用 NavigationController 来管理会话历史。这个控制器负责:

  • 记录历史记录条目(SessionHistoryEntry)
  • 控制页面导航方向
  • 管理与渲染进程之间的切换(跨进程导航)

3.2 SessionHistoryEntry

每条历史记录不仅包含页面 URL,还记录:

  • 页面状态(滚动位置、表单数据等)
  • 页面是否为跨域页面
  • 页面来源(是用户点击链接跳转,还是脚本跳转)

这样,即便用户返回到很久之前的页面,浏览器也能尽量还原页面原貌。

3.3 跨进程导航

如果用户在多站点间切换(如从 example.comgoogle.com),出于安全性考虑,浏览器会将页面分配到不同的渲染进程。此时,后退或前进操作会触发“跨进程导航”,需要更复杂的调度机制。


四、模拟实现

const backStack = [];
const forwardStack = [];
let currentPage = "A";

function visit(page) {
    backStack.push(currentPage);
    currentPage = page;
    forwardStack.length = 0;
    console.log("Visit:", currentPage);
}

function back() {
    if (backStack.length > 0) {
        forwardStack.push(currentPage);
        currentPage = backStack.pop();
        console.log("Back to:", currentPage);
    }
}

function forward() {
    if (forwardStack.length > 0) {
        backStack.push(currentPage);
        currentPage = forwardStack.pop();
        console.log("Forward to:", currentPage);
    }
}

// 示例
visit("B");   // 当前 A -> B
visit("C");   // 当前 B -> C
back();       // 当前 C -> B
back();       // 当前 B -> A
forward();    // 当前 A -> B

五、单页应用中的前进后退

在传统页面中,浏览器自动处理历史记录。但在单页应用(SPA)中,页面不会刷新,所有状态由 JavaScript 管理。这就需要使用 pushStatepopstate 来手动控制导航行为:

// 添加新的历史记录
history.pushState({ page: 2 }, "Title 2", "/page2");

// 监听用户点击“后退”按钮的行为
window.addEventListener("popstate", function (event) {
    console.log("User navigated to:", event.state);
});

结语✒️

知识点+1✨✨✨

猫抓爱心.gif

❌