JSyncQueue——一个开箱即用的鸿蒙异步任务同步队列

作者:江澎涌日期:2026/1/31

零、JSyncQueue

JSyncQueue 是一个开箱即用的鸿蒙异步任务同步队列。

项目地址:github.com/zincPower/J…

一、JSyncQueue 有什么作用

在鸿蒙应用开发中,有时需要让多个异步任务按顺序执行,例如状态的转换处理,如果不加控制,会因为执行顺序混乱而产生一些莫名其妙的问题。 所以 JSyncQueue 提供了一个简洁的解决方案:

  • 保证顺序执行:所有任务严格按照入队顺序执行,即使任务内部有异步操作也能保证顺序
  • 两种执行模式:支持 "立即执行" 和 "延时执行" 两种模式,可以满足不同场景需求
  • 两种任务类型:支持向同步队列添加 "Message 类型任务" 和 "Runnable 类型任务"
  • 任务取消和管理:可随时取消指定任务或清空整个队列
  • 获取任务结果:通过任务的 getResult() 获取执行结果

项目架构如下图所示:

二、如何安装 JSyncQueue

第一种方式: 在需要使用 JSyncQueue 的模块中运行以下命令

1ohpm install jsyncqueue
2

第二种方式: 在需要使用 JSyncQueue 的模块 oh-package.json5 中添加以下依赖

1{
2  "name": "sample",
3  "version": "1.0.0",
4  "description": "Please describe the basic information.",
5  "main": "",
6  "author": "",
7  "license": "",
8  "dependencies": {
9    "jsyncqueue": "1.0.0" // 添加这一行,请根据需要修改版本号
10  }
11}
12

三、JSyncQueue API 介绍

3-1、JSyncQueue 类

构造函数

1constructor(queueName: string)
2

创建一个同步队列实例。

  • queueName: 队列名称,用于标识和调试

方法

方法参数返回值说明
post(runnable)runnable: (taskId: number) => Promise<Any>Task立即执行闭包
postDelay(runnable, delay)runnable: (taskId: number) => Promise<Any>, delay: numberTask延时 delay 毫秒执行闭包
sendMessage(message)message: MessageTask立即发送消息
sendMessageDelay(message, delay)message: Message, delay: numberTask延时 delay 毫秒发送消息
cancel(taskId)taskId: numbervoid取消指定任务
clear()-void清空队列中所有等待的任务
dumpInfo()-string获取队列调试信息
onHandleMessage(message, taskId)message: Message, taskId: numberPromise<Any>消息处理方法,子类可重写

属性

属性类型说明
queueNamestring队列名称(只读)
lengthnumber当前队列中的任务数量(只读)

3-2、Message 接口

1interface Message {
2  what: string   // 消息类型
3  data: Any      // 消息数据
4}
5

3-3、Task 接口

所有添加的任务,包括“Message 类型任务”和“Runnable 类型任务”,均会返回该类型实例,通过该实例可以“取消任务”、“获取任务结果”、“任务 Id”。

1interface Task {
2  cancel(): void                  // 取消任务
3  getResult(): Promise<Any>       // 获取任务结果
4  getTaskId(): number             // 获取任务 ID
5}
6

3-4、异常类型

JSyncQueueCancelException

当任务被取消时,会抛出该类型的异常。

1interface JSyncQueueCancelException {
2  message: string
3}
4

JSyncQueueException

当 JSyncQueue 内部发生异常时,会抛出该类型的异常。

值得注意:使用者编写的逻辑中抛出的异常会原封不动的抛到 Task.getResult().catch 中,而不是以 JSyncQueueException 类型抛出

1interface JSyncQueueException {
2  message: string
3}
4

四、如何使用 JSyncQueue

4-1、使用 JSyncQueue 创建同步队列

如果你处理的场景均是简单的一次性任务,那么直接使用 JSyncQueue 创建一个同步队列,并压入 Runnable 闭包即可。

以下代码展示的逻辑细节:

  • 代码中使用了 delay 函数模拟了两次耗时操作,并且返回结果
  • 外部通过 Task 类型实例接收返回结果,并且打印
  • 在第四次循环(即 i 为 3)的时候,会模拟抛出异常,异常内容会原封不动的抛到 catch

值得注意:

  • 立即执行任务会严格按入队顺序执行
  • 任务结果的接收处理(即对 Task.getResult() 的处理)和 JSyncQueue 对任务的处理是不保证顺序的,因为 Task.getResult() 的处理已不在队列范围内
1immediatelyJSyncQueue: JSyncQueue = new JSyncQueue("ImmediatelyJSyncQueue")
2for (let i = 0; i < 5; ++i) {
3  const task = this.immediatelyJSyncQueue.post(async () => {
4    const delayTime1 = Math.round(Math.random() * 500)
5    Log.i(TAG, [`【添加5个Runnable】执行逻辑 i=${i} 第一段 将会模拟耗时=${delayTime1}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
6    await this.delay(delayTime1)
7
8    if (i == 3) {
9      throw { message: "模拟异常" } as Error
10    }
11
12    const delayTime2 = Math.round(Math.random() * 500)
13    Log.i(TAG, [`【添加5个Runnable】执行逻辑 i=${i} 第二段 将会模拟耗时=${delayTime2}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
14    await this.delay(delayTime2)
15
16    return [`jiangpengyong-添加5个Runnable ${i}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md)
17  })
18  task.getResult()
19    .then((result) => {
20      Log.i(TAG, [`【添加5个Runnable-执行成功】i=${i} result=${result}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
21    })
22    .catch((e: Error) => {
23      Log.e(TAG, [`【添加5个Runnable-执行异常】i=${i} e=${JSON.stringify(e)}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
24    })
25    .finally(() => {
26      Log.i(TAG, [`【添加5个Runnable-执行结束】i=${i}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
27    })
28}
29
30// ========================================= 输出日志 =========================================
31// 【添加5个Runnable】执行逻辑 i=0 第一段 将会模拟耗时=239
32// 【添加5个Runnable】执行逻辑 i=0 第二段 将会模拟耗时=315
33// 【添加5个Runnable】执行逻辑 i=1 第一段 将会模拟耗时=379
34// 【添加5个Runnable-执行成功】i=0 result=jiangpengyong-添加5个Runnable 0
35// 【添加5个Runnable-执行结束】i=0
36// 【添加5个Runnable】执行逻辑 i=1 第二段 将会模拟耗时=391
37// 【添加5个Runnable】执行逻辑 i=2 第一段 将会模拟耗时=499
38// 【添加5个Runnable-执行成功】i=1 result=jiangpengyong-添加5个Runnable 1
39// 【添加5个Runnable-执行结束】i=1
40// 【添加5个Runnable】执行逻辑 i=2 第二段 将会模拟耗时=395
41// 【添加5个Runnable】执行逻辑 i=3 第一段 将会模拟耗时=478
42// 【添加5个Runnable-执行成功】i=2 result=jiangpengyong-添加5个Runnable 2
43// 【添加5个Runnable-执行结束】i=2
44// 【添加5个Runnable】执行逻辑 i=4 第一段 将会模拟耗时=166
45// 【添加5个Runnable-执行异常】i=3 e={"message":"模拟异常"}
46// 【添加5个Runnable-执行结束】i=3
47// 【添加5个Runnable】执行逻辑 i=4 第二段 将会模拟耗时=33
48// 【添加5个Runnable-执行成功】i=4 result=jiangpengyong-添加5个Runnable 4
49// 【添加5个Runnable-执行结束】i=4
50

取消同步任务

通过返回的 Task 类型实例调用 cancel 方法可以进行取消任务。

下面的代码会取消第四次任务,所以在日志中会看到对应的取消异常,并且不会执行该任务。

1let task: Task | undefined
2for (let i = 0; i < 5; ++i) {
3  const tempTask = this.immediatelyJSyncQueue.post(async () => {
4    const delayTime1 = Math.round(Math.random() * 500)
5    Log.i(TAG, [`【移除Runnable】执行逻辑 i=${i} 第一段 将会模拟耗时=${delayTime1}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
6    await this.delay(delayTime1)
7
8    const delayTime2 = Math.round(Math.random() * 500)
9    Log.i(TAG, [`【移除Runnable】执行逻辑 i=${i} 第二段 将会模拟耗时=${delayTime2}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
10    await this.delay(delayTime2)
11
12    if (i == 2) {
13      throw { message: "模拟异常" } as Error
14    }
15    return [`jiangpengyong-移除Runnable ${i}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md)
16  })
17  tempTask.getResult().then((result) => {
18    Log.i(TAG, [`【移除Runnable】执行成功 i=${i} result=${result}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
19  }).catch((e: Any) => {
20    Log.e(TAG, [`【移除Runnable】执行异常 i=${i} e=${JSON.stringify(e)}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
21  }).finally(() => {
22    Log.i(TAG, [`【移除Runnable】执行完成 i=${i}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
23  })
24  if (i == 3) {
25    task = tempTask
26  }
27}
28Log.i(TAG, `【移除Runnable】取消任务 task=${JSON.stringify(task)}`)
29task?.cancel()
30
31// ========================================= 输出日志 =========================================
32// 【移除Runnable】执行逻辑 i=0 第一段 将会模拟耗时=263
33// 【移除Runnable】取消任务 task={"taskId":13,"queue":{},"promise":{}}
34// 【移除Runnable】执行异常 i=3 e={"message":"Cancel task by cancel function."}
35// 【移除Runnable】执行完成 i=3
36// 【移除Runnable】执行逻辑 i=0 第二段 将会模拟耗时=474
37// 【移除Runnable】执行逻辑 i=1 第一段 将会模拟耗时=318
38// 【移除Runnable】执行成功 i=0 result=jiangpengyong-移除Runnable 0
39// 【移除Runnable】执行完成 i=0
40// 【移除Runnable】执行逻辑 i=1 第二段 将会模拟耗时=6
41// 【移除Runnable】执行逻辑 i=2 第一段 将会模拟耗时=406
42// 【移除Runnable】执行成功 i=1 result=jiangpengyong-移除Runnable 1
43// 【移除Runnable】执行完成 i=1
44// 【移除Runnable】执行逻辑 i=2 第二段 将会模拟耗时=212
45// 【移除Runnable】执行逻辑 i=4 第一段 将会模拟耗时=226
46// 【移除Runnable】执行异常 i=2 e={"message":"模拟异常"}
47// 【移除Runnable】执行完成 i=2
48// 【移除Runnable】执行逻辑 i=4 第二段 将会模拟耗时=439
49// 【移除Runnable】执行成功 i=4 result=jiangpengyong-移除Runnable 4
50// 【移除Runnable】执行完成 i=4
51

延时执行 Runnable 类型任务

添加延时任务只需改用 postDelay 方法并传入延时参数

  • 下面代码记录了添加任务到真正执行的延时,通过 realDelay 参数可以查看
  • 使用了 delay 函数模拟了两次耗时操作,并模拟返回了处理结果
  • 第四次任务抛出了异常,异常消息会原封不动的在 catch 的日志展示
  • 因为延时任务的添加是按索引进行累加的,所以添加顺序其实并没变化,从最后的日志输出可以看到保证了执行顺序
1for (let i = 0; i < 5; ++i) {
2  const startTime = systemDateTime.getTime(false)
3  const delayTime = i * 100
4  const task = this.delayJSyncQueue.postDelay(async () => {
5    const endTime = systemDateTime.getTime(false)
6    const realDelay = endTime - startTime
7    const delayTime1 = Math.round(Math.random() * 500)
8    Log.i(TAG, [`【添加5个Runnable】执行逻辑 delay=${delayTime} realDelay=${realDelay} i=${i} 第一段 将会模拟耗时=${delayTime1}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
9    await this.delay(delayTime1)
10
11    const delayTime2 = Math.round(Math.random() * 500)
12    Log.i(TAG, [`【添加5个Runnable】执行逻辑 i=${i} 第二段 将会模拟耗时=${delayTime2}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
13    await this.delay(delayTime2)
14
15    if (i == 3) {
16      throw { message: "模拟异常" } as Error
17    }
18    return [`jiangpengyong-添加5个Runnable ${i}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md)
19  }, delayTime)
20  task.getResult()
21    .then((result) => {
22      Log.i(TAG, [`【添加5个Runnable】执行成功 i=${i} result=${result}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
23    })
24    .catch((e: Error) => {
25      Log.e(TAG, [`【添加5个Runnable】执行异常 i=${i} e=${JSON.stringify(e)}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
26    })
27    .finally(() => {
28      Log.i(TAG, [`【添加5个Runnable】执行结束 i=${i}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
29    })
30}
31
32// ========================================= 输出日志 =========================================
33// 【添加5个Runnable】执行逻辑 delay=0 realDelay=1 i=0 第一段 将会模拟耗时=473
34// 【添加5个Runnable】执行逻辑 i=0 第二段 将会模拟耗时=410
35// 【添加5个Runnable】执行逻辑 delay=100 realDelay=888 i=1 第一段 将会模拟耗时=178
36// 【添加5个Runnable】执行成功 i=0 result=jiangpengyong-添加5个Runnable 0
37// 【添加5个Runnable】执行结束 i=0
38// 【添加5个Runnable】执行逻辑 i=1 第二段 将会模拟耗时=204
39// 【添加5个Runnable】执行逻辑 delay=200 realDelay=1272 i=2 第一段 将会模拟耗时=410
40// 【添加5个Runnable】执行成功 i=1 result=jiangpengyong-添加5个Runnable 1
41// 【添加5个Runnable】执行结束 i=1
42// 【添加5个Runnable】执行逻辑 i=2 第二段 将会模拟耗时=36
43// 【添加5个Runnable】执行逻辑 delay=300 realDelay=1721 i=3 第一段 将会模拟耗时=475
44// 【添加5个Runnable】执行成功 i=2 result=jiangpengyong-添加5个Runnable 2
45// 【添加5个Runnable】执行结束 i=2
46// 【添加5个Runnable】执行逻辑 i=3 第二段 将会模拟耗时=483
47// 【添加5个Runnable】执行逻辑 delay=400 realDelay=2686 i=4 第一段 将会模拟耗时=9
48// 【添加5个Runnable】执行异常 i=3 e={"message":"模拟异常"}
49// 【添加5个Runnable】执行结束 i=3
50// 【添加5个Runnable】执行逻辑 i=4 第二段 将会模拟耗时=395
51// 【添加5个Runnable】执行成功 i=4 result=jiangpengyong-添加5个Runnable 4
52// 【添加5个Runnable】执行结束 i=4
53

取消延时任务

延时任务的取消操作和立即执行的取消操作是完全一样的,都是通过返回的 Task 实例调用 cancel 方法,这里就不再赘述。

4-2、继承 JSyncQueue 创建同步队列

如果你的同步逻辑需要集中管理或进行复用,可以考虑 Message 类型任务。

处理 Message 类型任务,需要继承 JSyncQueue 实现 onHandleMessage 方法,在该方法中会按入队顺序接收到 Message

  • 通过 Message.what 属性区分不同类别消息实现不同处理逻辑
  • 通过 Message.data 属性可以获取外部传入的数据,数据类型是 Any 可以是任意类型数据,使用者自行转换为真实类型进行逻辑处理

具体操作如下:

  • 定义一个 ImmediatelyQueue 类继承 JSyncQueue ,实现 onHandleMessage 方法
  • 创建一个 ImmediatelyQueue 实例,并通过这个实例进行发送 Message 消息,同步队列会按入队顺序一个个进行分发给该实例的 onHandleMessage 方法进行处理
1// 自定义 JSyncQueue
2export class ImmediatelyQueue extends JSyncQueue {
3  private count = 0
4
5  async onHandleMessage(message: Message): Promise<Any> {
6    switch (message.what) {
7      case "say_hello": {
8        const name = message.data["name"]
9        this.count += 1
10
11        const delayTime1 = Math.round(Math.random() * 500)
12        Log.i("ImmediatelyQueue", `【say_hello】执行逻辑 第一段 将会模拟耗时=${delayTime1}`)
13        await this.delay(delayTime1)
14
15        const delayTime2 = Math.round(Math.random() * 500)
16        Log.i("ImmediatelyQueue", `【say_hello】执行逻辑 第二段 将会模拟耗时=${delayTime2}`)
17        await this.delay(delayTime2)
18
19        if (this.count % 10 == 5) {
20          throw { message: "模拟异常" }
21        }
22        return `你好,${name}。这是第${this.count}次打招呼。`
23      }
24      // ... 其他 what 处理逻辑
25    }
26    return undefined
27  }
28
29  private async delay(ms: number) {
30    return new Promise<Any>(resolve => setTimeout(resolve, ms))
31  }
32}
33
34// 使用逻辑
35immediatelyQueue: JSyncQueue = new ImmediatelyQueue("ImmediatelyQueue")
36for (let i = 0; i < 5; ++i) {
37  const tempTask = this.immediatelyQueue.sendMessage({
38    what: `say_hello`,
39    data: { name: '江澎涌', age: 20 + i },
40  })
41  tempTask.getResult()
42    .then((result) => {
43      Log.i(TAG, [`【添加5个Message】执行成功 i=${i} result=${result}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
44    })
45    .catch((e: Error) => {
46      Log.e(TAG, [`【添加5个Message】执行异常 i=${i} e=${JSON.stringify(e)}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
47    })
48    .finally(() => {
49      Log.i(TAG, [`【添加5个Message】执行结束i=${i}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
50    })
51}
52// ========================================= 输出日志 =========================================
53// onHandleMessage message={"what":"say_hello","data":{"name":"江澎涌","age":20}}
54// 【say_hello】执行逻辑 第一段 将会模拟耗时=92
55// 【say_hello】执行逻辑 第二段 将会模拟耗时=143
56// onHandleMessage message={"what":"say_hello","data":{"name":"江澎涌","age":21}}
57// 【say_hello】执行逻辑 第一段 将会模拟耗时=276
58// 【say_hello】执行逻辑 第二段 将会模拟耗时=377
59// onHandleMessage message={"what":"say_hello","data":{"name":"江澎涌","age":22}}
60// 【say_hello】执行逻辑 第一段 将会模拟耗时=120
61// 【say_hello】执行逻辑 第二段 将会模拟耗时=223
62// onHandleMessage message={"what":"say_hello","data":{"name":"江澎涌","age":23}}
63// 【say_hello】执行逻辑 第一段 将会模拟耗时=424
64// 【say_hello】执行逻辑 第二段 将会模拟耗时=444
65// onHandleMessage message={"what":"say_hello","data":{"name":"江澎涌","age":24}}
66// 【say_hello】执行逻辑 第一段 将会模拟耗时=181
67// 【say_hello】执行逻辑 第二段 将会模拟耗时=402
68

移除 Message 消息

使用 sendMessage 方法压入 “Message 类型任务” 同样会返回 Task 类型实例,调用该实例的 cancel 方法就可以取消该任务。

下列代码会取消第二个任务,所以不会看到 "age":11 的消息。

1let task: Task | undefined
2for (let i = 0; i < 5; ++i) {
3  const tempTask = this.immediatelyQueue.sendMessage({
4    what: `remove_message`,
5    data: { name: 'jiang peng yong', age: 10 + i },
6  })
7  tempTask.getResult().then((result) => {
8    Log.i(TAG, [`【移除Message】执行成功 i=${i} result=${result}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
9  }).catch((e: Any) => {
10    Log.e(TAG, [`【移除Message】执行异常 i=${i} e=${JSON.stringify(e)}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
11  }).finally(() => {
12    Log.i(TAG, [`【移除Message】执行完成 i=${i}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
13  })
14  if (i == 1) {
15    task = tempTask
16  }
17}
18Log.i(TAG, `【移除Message】取消任务 task=${JSON.stringify(task)}`)
19task?.cancel()
20// ========================================= 输出日志 =========================================
21// onHandleMessage message={"what":"remove_message","data":{"name":"jiang peng yong","age":10}}
22// 【remove_message】执行逻辑 第一段 将会模拟耗时=497
23// 【remove_message】执行逻辑 第二段 将会模拟耗时=397
24// onHandleMessage message={"what":"remove_message","data":{"name":"jiang peng yong","age":12}}
25// 【remove_message】执行逻辑 第一段 将会模拟耗时=162
26// 【remove_message】执行逻辑 第二段 将会模拟耗时=283
27// onHandleMessage message={"what":"remove_message","data":{"name":"jiang peng yong","age":13}}
28// 【remove_message】执行逻辑 第一段 将会模拟耗时=193
29// 【remove_message】执行逻辑 第二段 将会模拟耗时=93
30// onHandleMessage message={"what":"remove_message","data":{"name":"jiang peng yong","age":14}}
31// 【remove_message】执行逻辑 第一段 将会模拟耗时=359
32// 【remove_message】执行逻辑 第二段 将会模拟耗时=145
33

延时执行 Message 类型任务

  • 定义一个 DelayQueue 类继承 JSyncQueue ,主要重写 onHandleMessage 方法,用于接收处理 Message
  • 创建 DelayQueue 实例,通过这个实例调用 sendMessageDelay 方法即可达到相应的延时效果
1export class DelayQueue extends JSyncQueue {
2  private count = 0
3
4  async onHandleMessage(message: Message): Promise<Any> {
5    Log.i("DelayQueue", `onHandleMessage message=${JSON.stringify(message)}`)
6    switch (message.what) {
7      case "say_hello": {
8        const name = message.data["name"]
9        this.count += 1
10
11        const delayTime1 = Math.round(Math.random() * 500)
12        Log.i("DelayQueue", `【say_hello】执行逻辑 第一段 将会模拟耗时=${delayTime1}`)
13        await this.delay(delayTime1)
14
15        const delayTime2 = Math.round(Math.random() * 500)
16        Log.i("DelayQueue", `【say_hello】执行逻辑 第二段 将会模拟耗时=${delayTime2}`)
17        await this.delay(delayTime2)
18
19        if (this.count % 10 == 5) {
20          throw { message: "模拟异常" }
21        }
22        return [`Hello,${name}. This is the ${this.count} th greeting.`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.th.md)
23      }
24    }
25    return undefined
26  }
27
28  private async delay(ms: number) {
29    return new Promise<Any>(resolve => setTimeout(resolve, ms))
30  }
31}
32
33delayQueue: JSyncQueue = new DelayQueue("DelayQueue")
34for (let i = 0; i < 5; ++i) {
35  const delayTime = i * 100
36  const task = this.delayQueue.sendMessageDelay({
37    what: `say_hello`,
38    data: { name: '江澎涌', age: 20 + i },
39  }, delayTime)
40  task.getResult()
41    .then((result) => {
42      Log.i(TAG, [`【添加5个Message】执行成功 i=${i} result=${result}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
43    })
44    .catch((e: Error) => {
45      Log.e(TAG, [`【添加5个Message】执行异常 i=${i} e=${JSON.stringify(e)}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
46    })
47    .finally(() => {
48      Log.i(TAG, [`【添加5个Message】执行结束i=${i}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
49    })
50}
51// ========================================= 输出日志 ========================================= 
52// onHandleMessage message={"what":"say_hello","data":{"name":"江澎涌","age":20}}
53// 【say_hello】执行逻辑 第一段 将会模拟耗时=356
54// 【say_hello】执行逻辑 第二段 将会模拟耗时=302
55// onHandleMessage message={"what":"say_hello","data":{"name":"江澎涌","age":21}}
56// 【say_hello】执行逻辑 第一段 将会模拟耗时=67
57// 【say_hello】执行逻辑 第二段 将会模拟耗时=344
58// onHandleMessage message={"what":"say_hello","data":{"name":"江澎涌","age":22}}
59// 【say_hello】执行逻辑 第一段 将会模拟耗时=339
60// 【say_hello】执行逻辑 第二段 将会模拟耗时=384
61// onHandleMessage message={"what":"say_hello","data":{"name":"江澎涌","age":23}}
62// 【say_hello】执行逻辑 第一段 将会模拟耗时=442
63// 【say_hello】执行逻辑 第二段 将会模拟耗时=392
64// onHandleMessage message={"what":"say_hello","data":{"name":"江澎涌","age":24}}
65// 【say_hello】执行逻辑 第一段 将会模拟耗时=443
66// 【say_hello】执行逻辑 第二段 将会模拟耗时=199
67

取消延时的 Message 类型任务

延时任务的取消操作和立即执行的取消操作是完全一样的,都是通过返回的 Task 实例调用 cancel 方法,这里就不再赘述。

同一队列压入 Message 类型任务和 Runnable 类型任务

JSyncQueue 同一实例压入 MessageRunnable 两种类型任务是支持的,会按照压入顺序进行执行和分发。

1// ImmediatelyQueue 源码就不再展示,需要可以移步 Github 上查阅
2immediatelyQueue: JSyncQueue = new ImmediatelyQueue("ImmediatelyQueue")
3for (let i = 0; i < 10; ++i) {
4  if (i % 2 == 0) {
5    this.immediatelyQueue.post(async () => {
6      const delayTime1 = Math.round(Math.random() * 500)
7      Log.i(TAG, [`【添加10个Message和Runnable】执行逻辑 i=${i} 第一段 将会模拟耗时=${delayTime1}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
8      await this.delay(delayTime1)
9
10      const delayTime2 = Math.round(Math.random() * 500)
11      Log.i(TAG, [`【添加10个Message和Runnable】执行逻辑 i=${i} 第二段 将会模拟耗时=${delayTime2}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
12      await this.delay(delayTime2)
13
14      if (i / 2 == 3) {
15        throw { message: "模拟异常" } as Error
16      }
17      return [`小朋友-添加10个Message和Runnable ${i}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md)
18    })
19  } else {
20    this.immediatelyQueue.sendMessage({
21      what: `say_hello`,
22      data: { name: '小朋友', age: i },
23    })
24  }
25}
26// ========================================= 输出日志 ========================================= 
27// 【添加10个Message和Runnable】执行逻辑 i=0 第一段 将会模拟耗时=416
28// 【添加10个Message和Runnable】执行逻辑 i=0 第二段 将会模拟耗时=41
29// onHandleMessage message={"what":"say_hello","data":{"name":"小朋友","age":1}}
30// 【say_hello】执行逻辑 第一段 将会模拟耗时=184
31// 【say_hello】执行逻辑 第二段 将会模拟耗时=63
32// 【添加10个Message和Runnable】执行逻辑 i=2 第一段 将会模拟耗时=451
33// 【添加10个Message和Runnable】执行逻辑 i=2 第二段 将会模拟耗时=223
34// onHandleMessage message={"what":"say_hello","data":{"name":"小朋友","age":3}}
35// 【say_hello】执行逻辑 第一段 将会模拟耗时=99
36// 【say_hello】执行逻辑 第二段 将会模拟耗时=27
37// 【添加10个Message和Runnable】执行逻辑 i=4 第一段 将会模拟耗时=273
38// 【添加10个Message和Runnable】执行逻辑 i=4 第二段 将会模拟耗时=193
39// onHandleMessage message={"what":"say_hello","data":{"name":"小朋友","age":5}}
40// 【say_hello】执行逻辑 第一段 将会模拟耗时=20
41// 【say_hello】执行逻辑 第二段 将会模拟耗时=231
42// 【添加10个Message和Runnable】执行逻辑 i=6 第一段 将会模拟耗时=46
43// 【添加10个Message和Runnable】执行逻辑 i=6 第二段 将会模拟耗时=198
44// onHandleMessage message={"what":"say_hello","data":{"name":"小朋友","age":7}}
45// 【say_hello】执行逻辑 第一段 将会模拟耗时=179
46// 【say_hello】执行逻辑 第二段 将会模拟耗时=0
47// 【添加10个Message和Runnable】执行逻辑 i=8 第一段 将会模拟耗时=131
48// 【添加10个Message和Runnable】执行逻辑 i=8 第二段 将会模拟耗时=401
49// onHandleMessage message={"what":"say_hello","data":{"name":"小朋友","age":9}}
50// 【say_hello】执行逻辑 第一段 将会模拟耗时=452
51// 【say_hello】执行逻辑 第二段 将会模拟耗时=40
52

4-3、取消队列中所有任务

JSyncQueue 实例调用 clear 方法,就会把队列中等待执行的任务,包括延时执行和立即执行的任务,全都取消。同时会抛出 JSyncQueueCancelException 类型异常。

1for (let i = 0; i < 5; ++i) {
2  const task = this.immediatelyQueue.post(async () => {
3    const delayTime1 = Math.round(Math.random() * 500)
4    Log.i(TAG, [`【清空队列】执行逻辑 i=${i} 第一段 将会模拟耗时=${delayTime1}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
5    await this.delay(delayTime1)
6
7    const delayTime2 = Math.round(Math.random() * 500)
8    Log.i(TAG, [`【清空队列】执行逻辑 i=${i} 第二段 将会模拟耗时=${delayTime2}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
9    await this.delay(delayTime2)
10
11    return [`小朋友-清空队列 ${i}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md)
12  })
13  task.getResult()
14    .then((result) => {
15      Log.i(TAG, [`【清空队列】执行成功 i=${i} result=${result}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
16    })
17    .catch((e: Error) => {
18      Log.e(TAG, [`【清空队列】执行异常 i=${i} e=${JSON.stringify(e)}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
19    })
20    .finally(() => {
21      Log.i(TAG, [`【清空队列】执行结束 i=${i}`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.i.md))
22    })
23}
24this.immediatelyQueue.clear()
25// ========================================= 输出日志 ========================================= 
26// 【清空队列】执行逻辑 i=0 第一段 将会模拟耗时=14
27// 【清空队列】执行异常 i=1 e={"message":"Cancel task by clear function."}
28// 【清空队列】执行异常 i=2 e={"message":"Cancel task by clear function."}
29// 【清空队列】执行异常 i=3 e={"message":"Cancel task by clear function."}
30// 【清空队列】执行异常 i=4 e={"message":"Cancel task by clear function."}
31// 【清空队列】执行结束 i=1
32// 【清空队列】执行结束 i=2
33// 【清空队列】执行结束 i=3
34// 【清空队列】执行结束 i=4
35// 【清空队列】执行逻辑 i=0 第二段 将会模拟耗时=125
36// 【清空队列】执行成功 i=0 result=小朋友-清空队列 0
37// 【清空队列】执行结束 i=0
38

五、作者博客

掘金:juejin.im/user/5c3033…

csdn:blog.csdn.net/weixin_3762…

公众号:微信搜索 "江澎涌"


JSyncQueue——一个开箱即用的鸿蒙异步任务同步队列》 是转载文章,点击查看原文


相关推荐


Python 线程局部存储:threading.local() 完全指南
哈里谢顿2026/1/21

一句话总结: threading.local() 是 Python 标准库提供的「线程局部存储(Thread Local Storage, TLS)」方案,让同一段代码在不同线程里拥有各自独立的变量空间,从而避免加锁,也避免了层层传参的狼狈。 1. 为什么需要线程局部存储? 在多线程环境下,如果多个线程共享同一个全局变量,就必须: 加锁 → 代码变复杂、性能下降; 或者层层传参 → 代码臃肿、可维护性差。 有些场景只想让线程各自持有一份副本,互不干扰: Web 服务:每个请求线程绑定自


绘制K线第二章:背景网格绘制
佛系打工仔2026/1/13

绘制K线第二章:背景网格绘制 在第一章的基础上,我们简单修饰一下,补充一个背景九宫格的绘制功能。这个功能可以让K线图更加清晰易读,帮助用户快速定位价格和时间。 二、网格配置 确定网格的行数和列数 在绘制网格之前,我们需要确定: 几行:将高度分成几等份(对应价格轴) 几列:将宽度分成几等份(对应时间轴) 例如:4列5行,表示宽度分成4等份,高度分成5等份。 在Config中配置 为了灵活配置网格,我们在 KLineConfig 中添加了两个字段: data class KLineConfig(


Linux系统安全及应用(账号权限管理、登录控制、弱口令、端口扫描)
晚风吹人醒.2026/1/5

目录 1. 账号管理与权限控制         1.1 基本安全措施:                 1.1.1 账号管理和文件权限                 1.1.2 密码安全控制                 1.1.3历史命令和自动注销         1.2 用户切换与提权: 2. 系统引导与登录控制         2.1 开关机安全控制:                 2.1.1 GRUB                 2.1.2 限制更改GRUB


算法竞赛中的数据结构:图
喜欢吃燃面2025/12/27

目录 一.图的基本概念1.图的定义2.图、树、线性表的联系与区别2.1 核心联系2.2 核心区别 二.图的分类1.按边的方向分类2.按边的权重分类3 .按顶点和边的数量分类4 .按连通性分类(针对无向图)5 .按强连通性分类(针对有向图)6 .其他特殊类型7.顶点的度(补充)8.路径及相关长度概念(补充)8.1 路径8.2 路径长度(无权图)8.3 带权路径长度(带权图)8.4 核心区别对比 三.邻接矩阵1.邻接矩阵【注意】 四.邻接表五.链式前向星


ZooKeeper+Kafka
吉良吉影1232025/12/18

目录 一、Zookeeper 1.1 Zookeeper 概述 1.2 Zookeeper 工作机制 1.3 ZooKeeper 特点 1.4 Zookeeper 数据结构 1.5 ZooKeeper 应用场景 1.6 Zookeeper 选举机制 1.6.1 第一次启动选举机制 1.6.2 非第一次启动选举机制 Leader 的作用 1. 处理所有写请求(核心职责) 2. 主导 Leader 选举 3. 管理集群数据同步 4. 维护集群状态 Follower


编程界 语言神 : 赶紧起来学 Rust 了!
Pomelo_刘金2025/12/10

大家对 Rust 的印象 没接触过的: 编程界语言神 整天重构这重构那 还要 要干掉 c++ ?! 稍微了解过的: 学习曲线: 但实际上是: 第一个高峰是 借用检查器,第二个是异步,第三个是unsafe,第四个是宏怎么玩? 开始接触之后 编译器不让我写代码,怎么写都报错 写 rust 代码像是在跟 rust 编译器谈对象 , 我只是传个参数,你跟我讲所有权、借用、生命周期?” 写的代码上线之后,还不错哦 “别的语言项目上线流程” 内容: 编译 ✔ 测试(偶尔挂一两条)✔ 上线后:半


单片机手搓掌上游戏机(十六)—pico运行fc模拟器之程序修改烧录
Bona Sun2025/11/30

我们来山寨picosystem,毕竟79刀,有些地方还是要简化修改的。 到: https://github.com/fhoedemakers/PicoSystem_InfoNes 下载zip或者git clone都可以。 解压缩,用vscode 打开文件夹   修改的地方:  首先是那个VSYNC,也就是8引脚的一个输入信号,我能买到的st7789上都没有这个引脚,看了一下代码 就是等待它的下降沿,也就知道该刷下一屏了。  其实没多大作用,我孤陋寡闻,还没见过屏幕撕裂,


【Linux】进程信号(上半)
Lsir10110_2026/2/8

当我们想要强行终止掉前台进程的时候,只需要按下Ctrl+c即可,但是Ctrl+c是如何精准杀掉前台进程的? 一、信号概念 1.如何理解信号 假设点了一份外卖,外卖员到了楼下会给你发信息或者打电话,那么这通电话或者这个信息就是信号,也就是用来提醒你需要去做某事的一种通知手段。那么对照Linux系统,信号就是内核向进程发送的通知,提醒进程需要去完成某个任务。 2.信号的特点 对照外卖例子,当点完外卖,我们肯定不会一直在门口等着外卖员,而是先忙手中的事情,比如打游戏,那么这个过程就叫做异步


React 性能优化:图片懒加载
NEXT062026/2/17

引言 在现代 Web 应用开发中,首屏加载速度(FCP)和最大内容绘制(LCP)是衡量用户体验的核心指标。随着富媒体内容的普及,图片资源往往占据了页面带宽的大部分。如果一次性加载页面上的所有图片,不仅会阻塞关键渲染路径,导致页面长时间处于“白屏”或不可交互状态,还会浪费用户的流量带宽。 图片懒加载(Lazy Loading)作为一种经典的性能优化策略,其核心思想是“按需加载”:即只有当图片出现在浏览器可视区域(Viewport)或即将进入可视区域时,才触发网络请求进行加载。这一策略能显著减少首屏


Gemini 3.1 Pro 正式发布:一次低调更新,还是谷歌的关键反击?
IvanCodes2026/2/25

今天凌晨,谷歌发布了新一代模型——Gemini 3.1 Pro 没有大型发布会,没有提前预热,甚至连宣传节奏都显得克制。 很多人会把它看作 Gemini 3 的小版本升级,但从目前披露的测试数据和演示能力来看,这更像是一次结构性强化,而不是简单的参数迭代。 如果说 Gemini 3 是谷歌重新回到核心竞争区间的标志,那么 Gemini 3.1 Pro,则明显带着更强的实战优化意味。 它在几个关键方向上给出了非常明确的信号:谷歌不只是追赶者。 性能升级:从可用到强势竞争 这次升

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 XYZ博客