HarmonyOS Next IM实战:异步缺乏await导致的逻辑错误Bug处理

HarmonyOS Next IM实战:异步缺乏await导致的逻辑错误Bug处理
背景介绍

IMSDK开发过程中,逻辑特别复杂,拿消息拉取逻辑来说,通过序号拉取热消息列表,接着处理消息,遍历消息内容,根据不同消息类型进行不同处理,将最终消息插入到消息表,如果消息是新会话消息还需要将会话信息插入到会话表,将用户信息插入到用户表、用户成员表等,最后通知UI新消息更新。网络请求、数据库操作很多都是异步操作,在整个流程中很多异步操作都是需要等待执行完才执行下一步,很多时候稍不留神就会忘记使用await导致出现逻辑错误的莫名其妙的Bug。

当出现Bug后,很难根据现象定位到原因,只能重新梳理逻辑,查看是否有漏写await的地方,但是这样不仅效率低下,而且难免还是会有遗漏,有什么好办法呢?

Code Linter 登场

这个时候可以借助Code Linter扫描代码帮助我们发现潜在的问题。每次代码提交前使用Code Linter检查可能存在的风险。

Code Linter 使用

在项目中根路径下创建code-linter.json文件,文件配置内容格式如下:

{ "files": [ "**/*.ets" ], "ignore": [ "**/src/ohosTest/**/*", "**/src/test/**/*", "**/src/mock/**/*", "**/node_modules/**/*", "**/oh_modules/**/*", "**/build/**/*", "**/.preview/**/*" ], "ruleSet": [ "plugin:@performance/recommended", "plugin:@typescript-eslint/recommended" ], "rules": { "@typescript-eslint/return-await": "error", "@typescript-eslint/require-await": "error", "@typescript-eslint/await-thenable": "error", "@typescript-eslint/promise-function-async": "error" } } 

这里面主要三个层级:

  • files:指定检测哪些文件,一般是所有ets文件;
  • ignore:忽略文件,一般会忽略构建产物、测试文件等;
  • ruleSet:规则集合,本示例中配置了性能推荐和通用规则
  • rules:具体规则。

配置完成后在IDE中右键要检测模块,依次选择Code Linter、Full Linter:

在这里插入图片描述

最后会在Code Linter输出检查结果:

在这里插入图片描述

我们根据检测结果修改不符合规范的代码即可。

异步相关规则介绍

这里我们用到三个异步相关的code linter规则。

promise-function-async

# @typescript-eslint/promise-function-async 规则要求任何返回Promise的函数或方法标记为async。确保每个功能只能:

  • 返回被拒绝的 promise,或者
  • 抛出一个 Error 对象。

相比之下,非 asyncPromise 返回函数在技术上可以做到这两者。处理这些函数结果的代码通常需要处理这两种情况,这可能会变得复杂。此规则的实践消除了创建代码来处理这两种情况的要求。

promise-function-async规则的主要目的是:

  1. ​提高代码清晰度​​:明确标识返回 Promise 的函数
  2. ​防止常见错误​​:避免忘记处理异步操作
  3. ​统一代码风格​​:确保所有 Promise 返回函数使用一致的声明方式
  4. ​简化错误处理​​:确保 async 函数的自动错误传播机制
  5. ​增强类型安全​​:利用 TypeScript 类型系统验证异步行为

下面是正确使用示例,返回Promise的函数都被标记为async:

export const arrowFunctionReturnsPromise = async () => Promise.resolve('value'); export async function functionReturnsPromise() { return Promise.resolve('value'); } // An explicit return type that is not Promise means this function cannot be made async, so it is ignored by the rule export function functionReturnsUnionWithPromiseExplicitly( p: boolean ): string | Promise<string> { return p ? 'value' : Promise.resolve('value'); } export async function functionReturnsUnionWithPromiseImplicitly(p: boolean) { return p ? 'value' : Promise.resolve('value'); } 

下面是使用不规范示例:

export const arrowFunctionReturnsPromise = () => Promise.resolve('value'); export function functionReturnsPromise() { return Promise.resolve('value'); } export function functionReturnsUnionWithPromiseImplicitly(p: boolean) { return p ? 'value' : Promise.resolve('value'); } 

具体说明参考:
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide_promise-function-async-V5

await-thenable

@typescript-eslint/await-thenable 不允许对不是“Thenable”对象的值使用await关键字(“Thenable”表示某个对象拥有“then”方法,比如Promise)。

正确使用代码如下:

async function test() { await Promise.resolve('value'); } export { test }; 

不符合规范代码示例如下:

async function test() { await 'value'; } export { test }; 

具体文档参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide_await-thenable-V5

require-await

这个是我们最需要关注的规则,@typescript-eslint/require-await要求异步函数必须包含“await”。
规则的主要目的是:

  1. ​防止误用​​:避免在非异步值上使用 await,这通常是代码错误或误解
  2. ​提高代码清晰度​​:确保 await 只用于真正的异步操作
  3. ​优化性能​​:消除不必要的异步开销(微任务队列)
  4. ​类型安全​​:利用 TypeScript 类型系统检测无效的 await 使用

比如下面代码:

async function doSomething(): Promise<void> { return Promise.resolve(); } export async function foo() { doSomething(); } 

foo函数会被检测到少了await,最大程度的帮助我们发现了可能的漏洞。

具体文档参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide_require-await-V5

return-await

@typescript-eslint/return-await 要求异步函数返回“await”。
async 函数中,返回 promise 封装的值或直接返回值都是有效的,这两者最终都会产生具有相同履行值的 promise。返回值而不是 promise 封装的值可以有几个好处:

  • 返回等待的 promise 改进堆栈跟踪信息。
  • 当 return 语句在 try…catch 中时,等待 promise 可以捕获 promise 的拒绝,而不是将错误留给调用者。
  • return await promise; 就是 至少与直接返回 promise 一样快。
    return-await规则强制一致处理是否在返回 promise 之前等待 promise。
    return-await规则有四种配置:
  • never :不允许等待任何返回的 promise。
  • error-handling-correctness-only:在错误处理上下文中,规则强制必须等待返回的 promise。在普通上下文中,规则不会强制执行有关是否等待返回的 promise 的任何特定行为。
  • in-try-catch:在错误处理上下文中,规则强制必须等待返回的 promise。在普通上下文中,规则强制 _ 不得 _ 等待返回的 promise。 */
  • always:要求等待所有返回的 promise。

return-await规则中的选项区分 “普通上下文” 和 “错误处理上下文”。错误处理上下文是返回未等待的 promise 会导致与异常/拒绝有关的意外控制流的任何地方。

  • 如果你在 try 块内返回一个 promise,则应该等待它以按预期触发后续的 catchfinally 块。
  • 如果你在 catch 块内返回一个 promise,并且有一个 finally 块,则应该等待它以按预期触发 finally 块。
  • 如果你在 usingawait using 声明与其范围结束之间返回一个 promise,则应该等待它,因为它的行为相当于封装在 try 块中后跟 finally 的代码。

普通上下文是可能返回 promise 的任何其他位置。在普通上下文中是否等待返回的 promise 的选择主要是风格上的。

选项普通上下文
(风格偏好🎨)
错误处理上下文
(捕获错误🐛)
我应该使用此选项吗?
alwaysreturn await promise;return await promise;✅ 是的!
in-try-catchreturn promise;return await promise;✅ 是的!
error-handling-correctness-only不关心 🤷return await promise;🟡 可以使用,但上述选项会更好。
neverreturn promise;return promise;
(⚠️ 这种行为可能有害⚠️)
❌ 不。此选项已弃用。

如下代码会被要求return 后跟await:

export async function validInTryCatch1() { try { return Promise.resolve('try'); } catch (e) { return Promise.resolve('catch'); } } 

最佳实践:

  1. 使用 "in-try-catch" 选项 - 这是最合理的默认设置
  2. 在 try-catch 块中总是使用 return await
  3. 在其他地方直接返回 Promise
  4. 避免在不需要错误处理的地方使用不必要的 await

具体文档参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide_return-await-V5

no-floating-promises

@typescript-eslint/no-floating-promises 要求正确处理Promise表达式。floating-promise是指在创建Promise时,没有使用任何代码来处理它可能引发的错误,这是一种不正确的使用方式。“floating” Promise 是在没有设置任何代码来处理它可能抛出的任何错误的情况下创建的。浮动 Promises 可能会导致几个问题,例如操作顺序不正确、忽略 Promise 拒绝等。

no-floating-promises规则将报告未按以下方式之一处理的 Promise 值语句:

  • 使用两个参数调用其 .then()
  • 使用一个参数调用其 .catch()
  • awaiting it
  • returning it
  • voiding it

no-floating-promises规则还会报告何时创建包含 Promise 的数组且未正确处理。解决此问题的主要方法是使用 Promise 并发方法之一创建单个 Promise,然后根据上述过程进行处理。这些方法包括:

  • Promise.all()
  • Promise.allSettled()
  • Promise.any()
  • Promise.race()

反例介绍:

export async function bar() { const promise = new Promise<string>(resolve => { resolve('value'); return 'finish'; }); promise; Promise.reject('value').catch(); await Promise.reject('value').finally(); ['1', '2', '3'].map(async x => x + '1'); } 

规则的核心意图总结:

  1. ​​防止静默失败​​
    • 确保 Promise 拒绝(rejection)不会被静默忽略
    • 避免未捕获的 Promise 错误导致应用状态不一致
  2. ​​提升代码可靠性​​
    • 强制开发者显式处理异步操作的结果
    • 防止因忘记错误处理而导致的崩溃
  3. ​​改善调试体验​​
    • 确保所有异步错误都能被追踪和记录
    • 避免难以复现的竞态条件问题
  4. ​​增强代码可维护性​​
    • 明确标识异步操作的消费点
    • 使异步数据流更易于理解和追踪

参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide_no-floating-promises-V5

no-misused-promises

@typescript-eslint/no-misused-promises规则旨在​​防止 Promise 在非异步上下文中被误用​​,确保 Promise 只在适合处理异步操作的场景中使用。这条规则是 TypeScript 项目中避免常见异步错误的关键防线。

规则的核心意图

  1. ​​防止条件语句中的误用​​
    • 检测在条件判断中直接使用 Promise(而非其解析值)
    • 避免因 Promise 对象始终为真值(truthy)导致的逻辑错误
  2. ​​防止逻辑表达式中的误用​​
    • 禁止在逻辑操作符(&&, ||, ??)中直接使用 Promise
    • 确保逻辑操作基于实际值而非 Promise 对象
  3. ​​确保回调函数正确使用​​
    • 防止在期望同步返回值的回调中返回 Promise
    • 避免在数组方法(如 forEach)中误用异步函数
  4. ​​保护 void 返回类型​​
    • 禁止在期望 void 返回类型的位置返回 Promise
    • 确保事件处理器等特殊场景的正确行为

问题场景分析
场景1:条件语句中的误用

// ❌ 错误:在条件判断中使用 Promise 对象 if (fetchUserData()) { // 始终执行,因为 Promise 对象总是 truthy console.log('正在获取用户数据...'); } // ✅ 正确:使用 await 获取实际值 async function checkUser() { const userData = await fetchUserData(); if (userData) { console.log('用户数据已加载'); } } 

场景2:逻辑表达式中的误用

// ❌ 错误:在逻辑操作符中使用 Promise const config = loadConfig() || defaultConfig; // 永远使用 loadConfig() // ✅ 正确:先解析 Promise 再比较 async function getConfig() { const loadedConfig = await loadConfig(); return loadedConfig ?? defaultConfig; } 

场景3:回调函数中的误用

// ❌ 错误:在数组方法中使用异步回调 [1, 2, 3].forEach(async (id) => { await deleteRecord(id); // 可能导致意外并发 }); // ✅ 正确:使用 for...of 顺序处理 async function deleteRecords() { for (const id of [1, 2, 3]) { await deleteRecord(id); } } // ✅ 正确:使用 Promise.all 并行处理 await Promise.all([1, 2, 3].map(id => deleteRecord(id))); 

场景4:void 返回类型的误用

// ❌ 错误:在事件处理器中返回 Promise const button = document.getElementById('submit'); button.addEventListener('click', () => { return submitForm(); // 事件处理器应返回 void }); // ✅ 正确:使用 void 明确忽略返回值 button.addEventListener('click', () => { void submitForm(); // 明确表示忽略 Promise }); // ✅ 正确:使用 async 并处理错误 button.addEventListener('click', async () => { try { await submitForm(); } catch (error) { showError(error); } }); 

具体文档参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide_no-misused-promises-V5

总结

本文介绍了在HarmonyOS 开发中由于异步使用不当导致的问题,通过code linter中五个具体规则帮助我们最大程度规避异步await导致的问题。

##鸿蒙核心技术##鸿蒙开发工具##DevEco Studio##
##社交##

Read more

OpenClaw 搭建全流程实战:从 0 部署到可控 AI Agent(附避坑与安全建议)

OpenClaw 搭建全流程实战:从 0 部署到可控 AI Agent(附避坑与安全建议)

近几个月,「AI Agent」成为技术圈的高频词,但大多数人停留在 Demo、插件和概念层。 真正能跑在本地 / 服务器、拥有真实权限、能持续执行任务的 Agent 并不多。 OpenClaw,正是目前少数几个工程完整、可部署、可二次开发的开源 AI Agent 框架之一。 这篇文章不讲愿景、不画饼,只讲怎么搭、怎么跑、怎么不翻车。 一、OpenClaw 到底是什么?先说清楚定位 一句话说明白: OpenClaw 是一个可部署在本地或服务器上的开源 AI Agent 框架,具备 Gateway(通信)、Dashboard(控制台)和 Skills(能力插件)三大核心模块。 和 ChatGPT / 插件的本质区别在于: 对比项普通 AI 工具OpenClaw运行位置云端本地

By Ne0inhk
人工智能:大模型高效推理与部署技术实战

人工智能:大模型高效推理与部署技术实战

人工智能:大模型高效推理与部署技术实战 1.1 本章学习目标与重点 💡 学习目标:掌握大语言模型推理与部署的核心技术,理解模型量化、推理加速、服务化部署的原理,能够完成开源大模型的高性能生产级部署。 💡 学习重点:精通INT4/INT8量化技术的应用,掌握vLLM等高性能推理框架的使用方法,学会搭建高并发的大模型API服务。 1.2 大模型推理部署的核心挑战 1.2.1 大模型推理的痛点分析 💡 预训练大模型通常具备数十亿甚至上百亿的参数量,直接进行推理会面临显存占用高、推理速度慢、并发能力弱三大核心问题。 * 显存占用高:以LLaMA-2-7B模型为例,FP16精度下显存占用约14GB,单张消费级显卡难以承载;而70B模型FP16精度显存占用更是超过140GB,普通硬件完全无法运行。 * 推理速度慢:自回归生成的特性导致模型需要逐token计算,单条长文本生成可能需要数十秒,无法满足实时应用需求。 * 并发能力弱:传统推理方式下,单卡同时处理的请求数极少,高并发场景下会出现严重的排队和延迟问题。 这些问题直接制约了大模型从实验室走向实际生产环境,因此高效

By Ne0inhk
医疗AI场景下算法编程的深度解析(2026新生培训讲稿)(八)

医疗AI场景下算法编程的深度解析(2026新生培训讲稿)(八)

第15章 模型融合与集成策略 在机器学习竞赛和实际应用中,模型融合(Model Ensemble)是提升预测性能的利器。通过组合多个不同的基模型,集成策略能够综合各个模型的优势,抵消单个模型的偏差和方差,从而获得比任何单一模型更稳定、更准确的预测结果。在医疗AI领域,模型融合同样具有重要价值——面对复杂多模态的医疗数据,单一模型往往难以全面捕捉所有信息,而融合多个异质模型可以提升诊断的鲁棒性和准确性。本章将从集成学习的基本思想出发,系统介绍常见的模型融合方法,包括投票法、平均法、Stacking、Blending等,并通过实战案例展示如何构建融合模型来提升疾病预测性能。 15.1 集成学习的基本思想 集成学习(Ensemble Learning)的核心思想是“三个臭皮匠,顶个诸葛亮”——通过结合多个学习器来完成学习任务,通常可以获得比单一学习器更优越的泛化性能。根据个体学习器的生成方式,集成学习主要分为两大类: * Bagging:并行训练多个独立的基学习器,然后通过平均或投票进行结合。典型代表是随机森林。Bagging主要降低方差。 * Boosting:串行训练基学习

By Ne0inhk
Flutter 三方库 huggingface_client 的鸿蒙化适配指南 - 连接全球最大 AI 开源社区、助力鸿蒙应用构建云端一体的大模型推理能力

Flutter 三方库 huggingface_client 的鸿蒙化适配指南 - 连接全球最大 AI 开源社区、助力鸿蒙应用构建云端一体的大模型推理能力

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 huggingface_client 的鸿蒙化适配指南 - 连接全球最大 AI 开源社区、助力鸿蒙应用构建云端一体的大模型推理能力 前言 在 OpenHarmony 鸿蒙应用全场景智能化的今天,AI 模型的获取与推理能力已成为应用的核心竞争力。如果你希望在鸿蒙应用中集成最前沿的文本生成、图像识别或语音转写功能,而又不想从零开始训练模型,那么 Hugging Face Hub 正是你不可或缺的“AI 军火库”。huggingface_client 作为一个专为 Dart/Flutter 设计的官方级客户端,提供了对 Hugging Face API 的深度封装。本文将指导你如何在鸿蒙端利用此库轻松调取全球顶尖的开源 AI 算力。 一、原原理分析 / 概念介绍 1.1

By Ne0inhk