Unity中如何将带回调的异步Web存储API转为同步返回函数
Unity Web存储异步转同步风格调用的正确实现方案
问题根源分析
直接赋值方案失效原因
APIController.WebAppStorageGet是异步调用,函数执行到return intvalue时,回调逻辑还未触发,因此返回的始终是初始的默认值。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,提问作者Марк
相关产品推荐
相关产品推荐

