如何合并简化Ionic中API调用前重复的Promise检查逻辑?
解决Ionic API调用中重复检查网络和认证的问题
看起来你已经意识到了重复代码的困扰——每次API调用都嵌套网络和认证检查确实繁琐,后期维护也麻烦。下面我给你几个实用方案,既能浓缩重复逻辑,又能保留connCheck和authCheck的独立性,方便单独使用。
第一步:优化基础检查函数
先把原来的检查函数用async/await重构,让代码更简洁易读,避免手动创建Promise的冗余:
优化网络检查函数
如果你的Angular版本是15+,推荐用firstValueFrom替代已废弃的toPromise():
import { firstValueFrom } from 'rxjs'; async connCheck(): Promise<boolean> { try { // 发送心跳请求验证网络连通性 await firstValueFrom( this.http.get(this.myURL() + '/heartbeat/', { responseType: 'text' }) ); return true; } catch (err) { // 请求失败说明无网络或服务器不可达 return false; } }
优化认证检查函数
用async/await简化逻辑,代码更直观:
async authCheck(message: string = 'Please login first!'): Promise<boolean> { const user = await this.storage.get('user'); // 直接返回布尔值,简化判断逻辑 return !!user; }
第二步:组合检查逻辑(核心方案)
把两个检查逻辑封装成统一的准备函数,所有API调用都能复用,还能统一处理失败提示(比如Ionic Toast):
async prepareForApi(authMessage?: string): Promise<boolean> { // 先检查网络,没网就跳过认证检查,节省资源 const hasNetwork = await this.connCheck(); if (!hasNetwork) { // 弹出无网络提示 const toast = await this.toastController.create({ message: 'No internet connection available', duration: 2000, position: 'bottom' }); await toast.present(); return false; } // 网络正常,再检查认证状态 const isAuthenticated = await this.authCheck(authMessage); if (!isAuthenticated) { // 弹出登录提示 const toast = await this.toastController.create({ message: authMessage || 'Please login first!', duration: 2000, position: 'bottom' }); await toast.present(); return false; } // 两项检查都通过 return true; }
第三步:简化API调用
现在有两种方式让你的API调用函数变得简洁:
方式一:用高阶函数包装API逻辑
创建一个包装函数,把检查逻辑和实际API调用解耦:
// 定义API调用的类型,方便类型提示 type ApiAction = () => Promise<any>; async wrapApiCall(apiAction: ApiAction, authMessage?: string): Promise<any | null> { const canProceed = await this.prepareForApi(authMessage); if (!canProceed) { // 检查不通过,返回null或抛出错误(根据业务需求调整) return null; } // 执行实际的API调用 return apiAction(); }
你的noteCreate函数可以简化成这样:
noteCreate(): Promise<any | null> { return this.wrapApiCall(async () => { // 只写实际的API请求逻辑 return firstValueFrom( this.http.post(`${this.myURL()}/notes`, { title: 'New Note', content: 'Hello World' }) ); }, 'Please login to create a note!'); // 可选自定义认证提示 }
方式二:用TypeScript装饰器(更优雅)
如果项目启用了TypeScript装饰器(需在tsconfig.json开启experimentalDecorators和emitDecoratorMetadata),可以用装饰器自动给API方法添加检查逻辑:
首先定义装饰器:
function ApiCheck(authMessage: string = 'Please login first!') { return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) { // 保存原方法的引用 const originalMethod = descriptor.value; // 重写方法,注入检查逻辑 descriptor.value = async function(...args: any[]) { const hasNetwork = await this.connCheck(); if (!hasNetwork) { const toast = await this.toastController.create({ message: 'No internet connection available', duration: 2000, position: 'bottom' }); await toast.present(); return null; } const isAuthenticated = await this.authCheck(authMessage); if (!isAuthenticated) { const toast = await this.toastController.create({ message: authMessage, duration: 2000, position: 'bottom' }); await toast.present(); return null; } // 执行原API方法 return originalMethod.apply(this, args); }; return descriptor; }; }
给API方法添加装饰器即可:
@ApiCheck('Please login to create a note!') async noteCreate(): Promise<any> { // 只写实际的API请求逻辑 return firstValueFrom( this.http.post(`${this.myURL()}/notes`, { title: 'New Note', content: 'Hello World' }) ); }
方案优势
- 复用性:重复的检查逻辑集中在一处,后续修改规则(比如换网络验证方式、调整认证逻辑)只需改一个地方。
- 独立性:
connCheck和authCheck依然可以单独调用,满足“部分场景仅需单一检查”的需求。 - 可读性:API方法只关注业务逻辑,代码更简洁,新人接手也更容易理解。
你可以根据项目习惯选择高阶函数或装饰器方案,两种都能很好地解决重复代码问题~
内容的提问来源于stack exchange,提问作者capcom-r
相关产品推荐
相关产品推荐

