canvas纹理加载错误必须在异步出口处处理,而非用try-catch包裹同步代码;image用onerror,fetch用catch或await+try,第三方库用其错误事件;失败后应绘制占位纹理、记录日志、设标志位,避免二次异步操作;全局监听unhandledrejection和error作为兜底。

Canvas 游戏引擎中纹理加载本质是异步资源请求(如 Image.onload、fetch 或 XMLHttpRequest),而 try-catch 默认不捕获这类异步错误。盲目包裹整个加载流程会失效,必须匹配异步执行模型。核心不是“加 try-catch”,而是“在哪加、怎么加、加完之后做什么”。
只对同步部分用 try-catch,异步错误必须进回调或 await
Canvas 中常见纹理加载方式有三种:直接创建 ``、用 `fetch` 读取 Blob、或通过 `createImageBitmap` 解码。它们都返回异步结果——try-catch 无法跨事件循环捕获这些操作内部抛出的错误。
例如:
- ❌ 错误写法(无效兜底):
try { const img = new Image(); img.src = 'tex.png'; } catch (e) { /* 不会触发 */ } - ✅ 正确思路:错误发生在 `img.onerror` 或 `fetch().catch()` 或 `await` 拒绝时,必须在对应异步出口处处理
为每种加载方式配专属错误出口
不同加载路径需不同兜底策略,不能统一套用一个 try-catch:
-
Image 加载:监听
onerror和onload,onerror中可 fallback 到默认占位图或记录日志 -
fetch + createImageBitmap:必须用
await fetch(...).then(r => r.ok ? r : Promise.reject(...))+try/catch,或链式.catch() -
第三方库(如 PIXI.Loader):遵循其错误事件机制(如
loader.onError.add(...)),而非自行 try-catch 外层调用
catch 块里只做安全降级,不发起新异步操作
纹理加载失败后,常见错误是在 catch 里立刻重试、切换 CDN、或弹提示框——这些动作本身可能出错,且会逃逸出当前 try-catch,导致二次崩溃。
推荐做法:
- 立即用 Canvas 2D 绘制一个纯色/网格占位纹理(无 DOM、无网络、无依赖)
- 记录错误详情(URL、status、type)到本地缓存或上报队列
- 设置标志位(如
textureLoadFailed[url] = true),避免重复加载 - 如需 UI 提示,调用已验证健壮的 toast 函数(该函数内部应已封装 try-catch)
全局兜底:监听 unhandledrejection 和 error
即使每个加载点都做了处理,仍可能漏掉未 await 的 Promise 或未绑定的 onerror。建议在引擎初始化时加两道防线:
window.addEventListener('unhandledrejection', e => { console.warn('未处理的纹理 Promise 拒绝:', e.reason); })window.addEventListener('error', e => { if (e.filename?.includes('tex') || e.message.includes('decode')) { /* 标记纹理相关全局异常 */ } })
这两者不替代局部处理,而是作为最后警报和归因依据。











