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

如何立即监听Firebase Auth Provider错误事件?弹窗关闭延迟问题

关于Firebase Auth signInWithPopup弹窗关闭延迟的问题

当使用Firebase Auth Provider的signInWithPopup方法时,用户点击关闭弹窗会返回error.code === 'auth/popup-closed-by-user',但存在一定延迟。请问该延迟产生的原因是什么?如何实现弹窗关闭时立即监听该错误事件?

以下是原使用signInWithPopup的代码:

export const signInWithSocial = async (type: string) => {
    let provider: any;

    if (type === SocialLoginType.google) {
        provider = googleProvider;
    } else if (type === SocialLoginType.facebook) {
        provider = facebookProvider;
        provider.setCustomParameters({
            display: 'popup'
        });
    } else if (type === SocialLoginType.twitter) {
        provider = twitterProvider;
        provider.setCustomParameters({
            lang: 'en'
        });
    } else if (type === SocialLoginType.apple) {
        provider = appleProvider;
        provider.addScope('email');
        provider.addScope('name');
    }

    auth.signInWithPopup(provider)
        .then(async (result) => {
            const { user } = result;
            const idToken = await user.getIdToken();

            window.localStorage.setItem('idToken', idToken);
            window.dispatchEvent(new Event('storage'));
        })
        .catch((error) => {
            console.log('--- Login Error: ' + JSON.stringify(error) + ' ---\n');

            const customEvent = new CustomEvent('stopSocialProcess');
            window.dispatchEvent(customEvent);
        });
};

延迟产生的原因

  • Firebase内部轮询机制:signInWithPopup底层通过固定间隔的轮询检测弹窗状态,而非实时监听关闭事件,轮询间隔直接导致了延迟。
  • 第三方提供商回调链路:关闭弹窗后,Firebase需要等待第三方身份提供商的回调确认,部分提供商的响应流程较长,会额外增加延迟。
  • 浏览器跨窗口通信限制:不同浏览器对跨窗口消息的处理逻辑有差异,部分场景下消息传递会出现排队等待,进一步拉长延迟时间。

实现实时监听弹窗关闭的方案

放弃依赖signInWithPopup的catch回调,改为手动创建弹窗并监听关闭事件,配合signInWithRedirect完成登录流程,代码示例如下:

export const signInWithSocial = async (type: string) => {
    let provider: any;
    // 配置弹窗尺寸与位置
    const popupWidth = 500;
    const popupHeight = 600;
    const left = window.screen.width / 2 - popupWidth / 2;
    const top = window.screen.height / 2 - popupHeight / 2;
    const popupOptions = `width=${popupWidth},height=${popupHeight},left=${left},top=${top},resizable=yes`;

    // 初始化对应身份提供商
    if (type === SocialLoginType.google) {
        provider = googleProvider;
    } else if (type === SocialLoginType.facebook) {
        provider = facebookProvider;
        provider.setCustomParameters({ display: 'popup' });
    } else if (type === SocialLoginType.twitter) {
        provider = twitterProvider;
        provider.setCustomParameters({ lang: 'en' });
    } else if (type === SocialLoginType.apple) {
        provider = appleProvider;
        provider.addScope('email');
        provider.addScope('name');
    }

    // 手动创建登录弹窗
    const authPopup = window.open('', '_blank', popupOptions);
    if (!authPopup) {
        console.error('无法打开登录弹窗,请检查浏览器弹窗设置');
        return;
    }

    // 短间隔轮询检测弹窗关闭状态
    const popupCheckInterval = setInterval(() => {
        if (authPopup.closed) {
            clearInterval(popupCheckInterval);
            // 立即触发自定义停止事件
            const customEvent = new CustomEvent('stopSocialProcess');
            window.dispatchEvent(customEvent);
            // 清理Firebase未完成的登录流程
            auth.signOut().catch(() => {});
        }
    }, 100); // 100ms间隔接近实时响应

    try {
        // 使用redirect方式触发登录流程
        await auth.signInWithRedirect(provider);
    } catch (error) {
        clearInterval(popupCheckInterval);
        console.log('--- Login Error: ' + JSON.stringify(error) + ' ---\n');
        const customEvent = new CustomEvent('stopSocialProcess');
        window.dispatchEvent(customEvent);
    }
};

// 在页面初始化时处理redirect登录结果
auth.getRedirectResult()
    .then(async (result) => {
        if (result?.user) {
            const idToken = await result.user.getIdToken();
            window.localStorage.setItem('idToken', idToken);
            window.dispatchEvent(new Event('storage'));
        }
    })
    .catch((error) => {
        console.log('--- Redirect Result Error: ' + JSON.stringify(error) + ' ---\n');
    });

方案说明

  • 手动创建弹窗后,通过100ms间隔的轮询检测弹窗状态,比Firebase内部的轮询更及时;
  • 配合signInWithRedirect和getRedirectResult完成完整登录流程,避免依赖signInWithPopup的延迟回调;
  • 弹窗关闭时立即触发自定义事件,实现实时响应需求。

内容的提问来源于stack exchange,提问作者Youth Dream

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 05:00:54