TaskPool方法不会阻塞UI,如果做上传图片的功能加载Loading记得使用TaskPool,Promise、Async/Await都会阻塞UI
【引言】
发现Promise可能会阻塞UI,尝试使用async或await,但发现它们仍然会导致阻塞。后来看到chaoxiaoshu回复的TaskPool方法,发现使用该方法后UI不再阻塞。因此,我特意编写了一个加载弹窗进行测试,结果同样显示,只有TaskPool方法不会阻塞UI。
【代码示例】
import { taskpool } from '@kit.ArkTS';
@Component
export struct MyDialog_1 {
@Prop dialogID: string
@State title: string = '加载中...'
build() {
Stack() {
Column() {
LoadingProgress()
.color(Color.White).width(100).height(100)
Text(this.title)
.fontSize(18).fontColor(0xffffff).margin({ top: 8 })
.visibility(this.title ? Visibility.Visible : Visibility.None)
}
}
.onClick(() => {
getContext(this).eventHub.emit(this.dialogID, "关闭弹窗")
})
.width(180)
.height(180)
.backgroundColor(0x88000000)
.borderRadius(10)
.shadow({
radius: 10,
color: Color.Gray,
offsetX: 3,
offsetY: 3
})
}
}
@Entry
@Component
struct Page28 {
@State time3: string = ""
@State isShowLoading: boolean = false
build() {
Stack() {
Column({ space: 20 }) {
Button("【方案一】测试Promise")
.type(ButtonType.Capsule)
.onClick(() => {
this.isShowLoading = true
this.time3 = 'loading...'
console.log("start call promise")
testPromise(100000000).then((time) => {
this.time3 = `耗时:${time}`
console.log("promise then")
this.isShowLoading = false
})
console.log("end call promise")
})
Button("【方案二】测试async await")
.type(ButtonType.Capsule)
.onClick(() => {
this.isShowLoading = true
this.time3 = 'loading...'
console.log("start call promise")
this.testPromise()
console.log("end call promise")
})
Button("【方案三】测试taskpool")
.type(ButtonType.Capsule)
.onClick(() => {
this.isShowLoading = true
this.time3 = 'loading...'
let task: taskpool.Task = new taskpool.Task(concurrentFunc, 100000000);
taskpool.execute(task);
task.onReceiveData((time: number) => {
this.time3 = `耗时:${time}`;
console.log("====end")
this.isShowLoading = false
})
})
Text(this.time3)
}.alignItems(HorizontalAlign.Start)
MyDialog_1().visibility(this.isShowLoading ? Visibility.Visible : Visibility.None)
}.width('100%').height('100%')
}
//耗时操作
async testPromise() {
let time = await testPromise(100000000)
time = new Date().getTime() - time
this.time3 = `耗时:${time}毫秒`
console.log("promise then")
this.isShowLoading = false
}
}
function testPromise(count: number): Promise<number> {
return new Promise<number>((resolve) => {
let time = Date.now().valueOf()
let num = 0
for (let i = 0; i < count; i++) {
+num
}
time = Date.now().valueOf() - time
resolve(time)
})
}
@Concurrent
function concurrentFunc(count: number): void {
let time = Date.now().valueOf()
let num = 0
for (let i = 0; i < count; i++) {
+num
}
time = Date.now().valueOf() - time
taskpool.Task.sendData(time);
}
【方案一:Promise】
优点:
易于理解:Promise的语法简单,易于理解和使用。
链式调用:可以通过.then进行链式调用,处理多个异步操作。
缺点:
阻塞UI:在执行耗时任务时,Promise会阻塞UI线程,导致Loading弹窗不能及时显示。
【方案二:Async/Await】
优点:
同步写法:Async/Await 使异步代码看起来像同步代码,更加直观。
错误处理:可以使用try/catch块处理错误,使代码更加清晰。
缺点:
阻塞UI:与Promise类似,Async/Await在执行耗时任务时仍会阻塞UI线程,导致Loading弹窗不能及时显示。
【方案三:TaskPool】
优点:
真正的异步:TaskPool可以将耗时任务放到独立的线程中执行,不会阻塞UI线程,保证了UI的流畅性。
数据通信:通过task.onReceiveData可以方便地接收任务结果。
缺点:
复杂度增加:引入了多线程处理,增加了代码的复杂度和维护成本。
【使用注意事项】
任务复杂度:
如果任务较为简单且不会长时间阻塞UI,可以考虑使用Promise或Async/Await。
如果任务较为复杂且耗时较长,建议使用TaskPool以保证UI的流畅性(例如,上传图片时显示加载中)。
代码可读性:
Promise和Async/Await的语法较为简单,适合初学者使用。
TaskPool需要对多线程有一定了解,适合有经验的开发者。
性能考虑:
TaskPool在处理大量或耗时任务时表现更优,可以显著提升应用性能。
Promise和Async/Await在小任务场景下更简洁高效。
【总结】
选择合适的异步操作方案至关重要。Promise和Async/Await适合处理简单的异步任务,而TaskPool则在处理复杂耗时任务时表现出色。根据实际需求,选择最适合的方案,能有效提升开发效率和用户体验。希望本文对您在异步操作的选择和使用上有所帮助。