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

Unity中如何将带回调的异步Web存储API转为同步返回函数

Unity Web存储异步转同步风格调用的正确实现方案

问题根源分析

  1. 直接赋值方案失效原因
    APIController.WebAppStorageGet是异步调用,函数执行到return intvalue时,回调逻辑还未触发,因此返回的始终是初始的默认值。

  2. TaskCompletionSource导致卡死原因
    Unity主线程调用.Result会阻塞当前线程,而Web存储的回调大概率需要在Unity主线程执行(WebGL环境下JS交互回调默认回到主线程),这就形成了死锁:主线程阻塞等待Task完成,回调却因主线程阻塞无法执行,最终导致Unity完全卡死。


方案1:使用Unity协程处理异步逻辑(推荐)

Unity协程天生适配异步等待场景,不会阻塞主线程,符合Unity开发习惯:

public static void GetInt(string key, int fallback, System.Action<int> onComplete)
{
    try
    {
        APIController.WebAppStorageGet(key, (strValue) =>
        {
            // 用TryParse避免格式错误抛出异常
            if (int.TryParse(strValue, out int result))
            {
                onComplete?.Invoke(result);
            }
            else
            {
                onComplete?.Invoke(fallback);
            }
        });
    }
    catch
    {
        onComplete?.Invoke(fallback);
    }
}

// 调用示例(在MonoBehaviour脚本中)
private IEnumerator Start()
{
    int score = 0;
    bool isLoaded = false;

    GetInt("score", 0, (result) =>
    {
        score = result;
        isLoaded = true;
    });

    // 等待异步加载完成
    yield return new WaitUntil(() => isLoaded);

    // 此处可安全使用score变量
    Debug.Log($"当前分数:{score}");
}

方案2:正确使用TaskCompletionSource(避免死锁)

如果要使用Task/await语法,绝对不能在主线程调用.Result或.Wait(),需配合Unity的异步上下文(Unity 2017.2+支持):

public static Task<int> GetInt(string key, int fallback = 0)
{
    var completionSource = new TaskCompletionSource<int>();

    try
    {
        APIController.WebAppStorageGet(key, (strValue) =>
        {
            if (int.TryParse(strValue, out int result))
            {
                completionSource.SetResult(result);
            }
            else
            {
                completionSource.SetResult(fallback);
            }
        });
    }
    catch (Exception e)
    {
        Debug.LogError($"读取存储数据失败:{e.Message}");
        completionSource.SetResult(fallback);
    }

    return completionSource.Task;
}

// 调用示例(在MonoBehaviour脚本中)
private async void Start()
{
    int score = await GetInt("score", 0);
    Debug.Log($"当前分数:{score}");
}

注意:Unity中async void仅适合事件回调或Start方法,其他场景优先使用async Task并通过协程等待。


关键注意事项

  • 禁止在Unity主线程用.Result/.Wait()阻塞等待Task,这是死锁的核心诱因。
  • 优先选择协程或async/await异步方式,避免阻塞主线程导致UI卡顿或程序崩溃。
  • 用int.TryParse替代直接int.Parse,增强代码鲁棒性,避免存储数据格式错误引发异常。

内容的提问来源于stack exchange,提问作者Марк

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 05:22:18