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

Firebase数据库写入后因while循环导致App挂起问题排查

问题根因与修复方案

1. 初始版本while循环导致App挂起的原因

JavaScript是单线程事件驱动模型,同步执行的死循环会完全占用主线程,所有异步任务(包括Firebase数据库请求回调、状态更新、UI渲染、定时器回调)都会被阻塞无法执行,所以is_user_dict和is_profile_ready永远不会被更新,程序自然会卡住。

2. 调整后报cannot read property "then" of undefined的原因

createProfile函数没有显式返回值,Firebase的set方法本身返回Promise,但你没有把这个Promise向外返回,所以函数默认返回undefined,自然无法调用.then方法。

3. 正确的异步实现方案

直接用async/await + Promise.race实现超时控制,完全替代不规范的while轮询:

第一步:修正createProfile函数,返回异步操作Promise

function createProfile() {
    let current_user_id = firebase.auth().currentUser.uid
    console.log('createProfile currentUser is ', current_user_id)
    // 直接返回set操作的Promise,操作完成后自动resolve
    return firebase.database().ref().child('profile').child(current_user_id).set({
        'user_dict': user_dict
    })
}

第二步:重写handleTestStart逻辑,用异步等待替代同步轮询

// 封装通用超时工具函数,指定时间内未完成就触发超时逻辑
function withTimeout(promise, timeoutMs, timeoutCallback) {
    return Promise.race([
        promise,
        new Promise((_, reject) => {
            setTimeout(() => {
                timeoutCallback?.()
                reject(new Error('操作超时'))
            }, timeoutMs)
        })
    ])
}

async function handleTestStart() {
    traceFunction()
    character.style.backgroundImage = "url(character.png)"
    left_button.style.visibility = 'visible'
    right_button.style.visibility = 'visible'
    showLogoAnimation()
    
    try {
        // 等待2秒,替代原来的外层setTimeout
        await new Promise(resolve => setTimeout(resolve, 2000))
        
        // 异步轮询等待is_user_dict准备完成,每次循环让出主线程,不会阻塞其他任务
        let start_time = Date.now()
        while (!is_user_dict) {
            if (Date.now() - start_time > 10000) {
                timeoutError()
                throw new Error('获取user_dict超时')
            }
            // 每次循环等待100ms,给其他异步任务留执行时间
            await new Promise(resolve => setTimeout(resolve, 100))
        }

        // 等待profile写入数据库完成,超时时间10秒
        await withTimeout(createProfile(), 10000, timeoutError)

        // 写入成功后执行后续逻辑
        hideLogoAnimation()
        condition_category_array.forEach(function (condition_category) {
            user_dict['more_info'].push(condition_category)
        })
        category = user_dict['more_info'][0]
        backup_user_dict = deepCopyObject(user_dict)
        nextQuestion()
    } catch (e) {
        console.error('流程执行失败', e)
    }
}

核心优化说明

  • 所有异步操作通过async/await等待完成,不会阻塞主线程执行
  • 用Promise.race实现规范的超时控制,替代无效的同步while轮询
  • 必须保留轮询逻辑时加入短时间等待,让出主线程给其他异步任务执行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 04:39:03