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

Google Identity Services异步Promise未等待resolve问题求助

问题描述

我在使用Google Identity Services搭建网页登录功能时遇到了问题:编写的async函数connectOAuth调用相关API后,其.then()方法会在Promise实际完成前提前执行。目前只能用setTimeout临时延迟关闭加载屏,但这并非合理方案,导致加载屏提前关闭破坏了网页整体CSS样式。

代码示例

const connectOAuth = async () => {
    /* global google */
    await google.accounts.id.initialize({
      client_id: "133396583135-1rar9q7nq2fotg5h6qk085i97s37hi5u.apps.googleusercontent.com",
      callback: handleCallBackResponse
    })
    await google.accounts.id.renderButton(document.getElementById("loginButton"), {theme: "outline", size: "large"})
    await google.accounts.id.prompt()
    return Promise.resolve()
  }
  
  useEffect(() => {
    connectOAuth().then(setTimeout(() => {setLoading(false)}, 1000))
  }, [])

解决方案

核心问题在于google.accounts.id.initialize、renderButton、prompt这些方法并不返回Promise,你用await无法真正等待它们的操作完成,导致connectOAuth函数直接进入resolved状态,.then()因此提前触发。同时你之前的.then()写法有误:.then(setTimeout(...))会立即执行setTimeout,而非等待Promise完成后执行。

正确实现方式:用Promise封装异步操作

把Google Identity Services的方法封装成Promise,确保await能等待操作完成:

const connectOAuth = async () => {
    /* global google */
    // 封装initialize:本身是同步操作,直接resolve确保后续操作依赖其状态
    await new Promise(resolve => {
        google.accounts.id.initialize({
            client_id: "133396583135-1rar9q7nq2fotg5h6qk085i97s37hi5u.apps.googleusercontent.com",
            callback: handleCallBackResponse
        });
        resolve();
    });

    // 封装renderButton:用requestAnimationFrame确保DOM渲染完成后再执行下一步
    await new Promise(resolve => {
        google.accounts.id.renderButton(document.getElementById("loginButton"), {theme: "outline", size: "large"});
        requestAnimationFrame(resolve);
    });

    // 封装prompt:利用其回调函数等待提示框状态稳定后resolve
    await new Promise(resolve => {
        google.accounts.id.prompt((notification) => {
            // 提示框显示/跳过/未显示时都视为操作完成
            if (notification.isNotDisplayed() || notification.isSkippedMoment() || notification.isDisplayed()) {
                resolve();
            }
        });
    });
};

useEffect(() => {
    connectOAuth().then(() => {
        setLoading(false); // 直接在Promise完成后关闭加载屏,无需setTimeout
    });
}, []);

关键细节说明

  1. initialize是同步操作,但封装成Promise能保证后续操作在其配置完成后执行。
  2. renderButton虽同步修改DOM,但requestAnimationFrame能等待浏览器完成重绘,确保按钮渲染就绪。
  3. prompt的回调会在提示框状态变化时触发,通过判断状态来resolve Promise,保证等待到提示框相关操作完成。

内容的提问来源于stack exchange,提问作者Vivek Y V

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 19:02:18