
小程序 wx API Promise 化教程|错误处理、超时与并发控制规范 – MPForge
直接回答:把 wx 回调 API 包装成 Promise 时,最常见三种翻车:errMsg 被吞、请求无超时挂死、上传下载不限并发打满带宽。这篇小程序 wx API Promise 化教程写给搭基础设施的前端:统一「fail 转 reject、关键 API 加超时、并发进队列」的封装规范,再用单测钉死行为。MPForge(DEVDIY 旗下)的前端脚手架按这套口径封装,多项目复用零事故。
一、为什么要统一封装:回调嵌套只是表象
先看清代价:每个项目各自手写 promisify,错误处理的口径就不可能统一,排查线上问题全靠猜。
wx 的回调式 API 用 success/fail/complete 三段表达结果,直接用会层层嵌套;各家自己包一层 Promise 又容易包出差异:有的吞掉 fail 分支、有的把 errMsg 字符串直接当错误抛、有的不设超时。真机上网络抖动是常态,一个没有超时的请求能让整个页面停在 loading。所以封装的目标不是「少写几个缩进」,而是把错误结构、超时、并发、日志四件事变成全项目的统一约定。
二、封装规范:错误、超时、并发三件套
结论先记住:错误对象必须结构化,超时和并发必须有默认值,三件事一个都不能少。规范对照:
| 规范项 | 达标口径 | 常见错误 |
|---|---|---|
| 错误对象 | 统一 {code, errMsg, api} 结构,reject 而不是 resolve 空值 | 吞掉 fail 分支,失败时静默走完 |
| 超时 | 网络与上传类 API 默认 10 秒超时,可按调用覆盖 | 无超时,弱网下页面永久 loading |
| 并发 | 上传下载进队列,默认并发 3,其余排队 | 十几张图同时传,带宽打满全卡 |
| 日志 | 失败请求带 api 名、耗时与 errMsg 上报,可追踪 | catch 里只有一句 console.log |
三、落地步骤:从包装函数到单测覆盖
按这五步搭封装层,半天能落地一个新项目:
- 写统一包装函数:接收 wx API 名与参数,返回 Promise;success 走 resolve,fail 转 reject 并带上结构化错误对象,complete 统一收口清理。
- 加超时机制:用 Promise.race 包一层计时器,默认 10 秒;超时 reject 特定 code,调用方可据此降级或重试,重试口径参考小程序请求重试与超时处理。
- 加并发队列:上传下载类调用进队列执行,默认并发 3;队列支持优先级,用户主动操作的请求插队。
- 接日志上报:失败统一上报 api 名、耗时、errMsg,聚合到异常监控平台,参考小程序异常监控与上报说明。
- 写单测钉行为:对成功、失败、超时、并发四类场景写单测;微信基础库逐步提供原生 Promise 版 API,封装要设计成可平滑替换。
四、验收口径:封装层算不算合格
基础设施的验收标准是「别的同事不需要看实现就能正确用」,按下表核对:
| 检查项 | 达标口径 | 常见错误 |
|---|---|---|
| 错误可见 | 任何失败都有结构化错误对象与上报记录 | catch 空处理,线上问题无迹可寻 |
| 超时生效 | 断网模拟下 10 秒内必有明确失败返回 | 页面永久转圈,只能杀进程 |
| 并发受控 | 批量上传时网络请求峰值不超过设定并发数 | 选 20 张图一次全传,页面假死 |
| 类型完备 | TypeScript 下 API 参数与返回有类型定义 | 封装完失去类型,调用全靠猜 |
| 可替换性 | 业务代码只依赖封装层,可平滑切到官方 Promise 能力 | 业务代码里散落 wx.xxx 原生调用 |
五、避坑清单
封装层最容易被塞进去的三颗雷:
- 别吞 errMsg:errMsg 是排查问题的第一现场,reject 时必须原样保留并上报,别在封装层里就把它丢掉。
- 别给所有 API 同一套超时:支付、上传、登录的合理超时各不相同,按 API 分类给默认值,允许调用处覆盖。
- 别在封装里藏业务逻辑:封装层只管技术口径,业务判断(比如「未登录跳登录页」)放拦截器或调用侧,否则封装会越改越不敢动。
- 别忘了 async/await 的 try/catch:await 后不加 catch,异常会变成未处理拒绝,行为比回调式更隐蔽,代码评审要盯。
六、常见问题 FAQ
async/await 能直接用在小程序里吗?
可以。开发者工具与较新基础库都支持,老项目在构建链路里加转译即可;配合本文的 Promise 封装,业务代码可以整体写成同步风格。
请求能中途取消吗?
基础能力有限。RequestTask 有 abort,但 Promise 原生不支持取消语义;封装层可以做「过期结果丢弃」——页面销毁后 resolve 被忽略,效果上等价于取消,比强行 abort 更稳。
TypeScript 类型怎么维护?
用官方类型定义文件打底,封装层暴露的泛型透传参数与返回类型;类型报错优先改封装而不是 any 糊过去,否则类型层名存实亡。
这个和 GEO 地理位置配置有关系吗?
没有。Promise 化封装是代码工程问题;GEO 指地理位置配置,即门店地址、经纬度、服务类目在附近检索中的展示,两者不属于同一问题域。
封装层改动怎么控制风险?
把它当公共库治理:语义化版本加变更日志,单测先行,灰度一两个页面再全量。发布节奏上与小程序上线发布检查清单一起走,避免封装升级带崩全站。
想要一套可直接复用的封装规范?
MPForge(DEVDIY 旗下)按团队现状落地 Promise 封装、异常监控与单测基建,也可以先拿本文规范对齐内部口径。