You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

新popstate事件触发时,如何终止前一次监听器的执行?

解决连续导航的并行执行问题

要解决连续点击导致的并行导航副作用,核心思路是终止上一次未完成的导航任务,可以通过AbortController中断异步请求,配合状态标记来控制流程,具体实现如下:


1. 新增全局状态控制变量

用来追踪当前是否在导航中,以及存储中断控制器:

let currentNavigationController = null;
let isNavigating = false;

2. 修改popstate监听器,加入中断逻辑

每次触发导航时,先终止上一次未完成的任务,再执行新的导航流程:

window.addEventListener("popstate", async () => {
    // 终止上一次正在进行的导航
    if (isNavigating) {
        currentNavigationController?.abort();
        isNavigating = false;
    }

    const body = document.body;
    const currentMain = document.querySelector("main");
    isNavigating = true;
    currentNavigationController = new AbortController();

    try {
        // 显示加载动画
        const spinnerMain = await createMain(spinner, currentNavigationController.signal);
        body.replaceChild(spinnerMain, currentMain);

        const route = window.location.hash.replace(/#/g, "");
        const page = pages[route];
        if (!page) {
            isNavigating = false;
            return;
        }

        // 创建目标页面并初始化
        const pageMain = await createMain(page, currentNavigationController.signal);
        const initiatedPage = await page.init(pageMain);

        // 确保当前导航未被中断,再更新DOM
        if (isNavigating) {
            body.replaceChild(initiatedPage, document.querySelector("main"));
        }
    } catch (err) {
        // 忽略中断错误,只处理其他异常
        if (err.name !== "AbortError") {
            console.error("导航失败:", err);
            // 可添加错误页面展示逻辑
        }
    } finally {
        // 仅当当前任务未被中断时,重置状态
        if (!currentNavigationController.signal.aborted) {
            isNavigating = false;
            currentNavigationController = null;
        }
    }
});

3. 改造createMain函数,支持请求中断

把中断信号传给fetch,让上一次的模板请求能被主动终止:

async function createMain(page, signal) {
    const template = await fetch(page.templateUrl, { signal });

    const main = document.createElement("main");
    main.classList.add(...page.classes);
    main.innerHTML = await template.text();

    return main;
}

额外注意点

  • 如果你的页面初始化(page.init)里也有异步操作(比如请求数据),最好也把signal传进去,让这些异步操作也能被中断,彻底终止上一次任务的所有流程。
  • 处理页面跳转的链接点击事件时,要确保每次点击都正确触发pushState和popstate事件,保证中断逻辑能生效。

内容的提问来源于stack exchange,提问作者Ero Stefano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 18:26:06