开发过程中被各种async弄到破防,因此手撸了几个工具类保证代码稳定性,话不多说直接上代码,文件后缀需要改成.ts比如PromiseUtil.ts
export function Promise_withResolver<T>() {
let resolve: (value: T) => void = undefined
let reject: (err: Error) => void = undefined
const promise = new Promise<T>((res, rej) => {
resolve = res
reject = rej
})
return {
promise: promise,
resolve: resolve,
reject: reject
}
}
该代码复刻js最新Promise的API,将resolver和reject从Promise中拆除,使数据的观察和触发分离,上场景
扫码组件初始化需要XComponent组件onLoad及权限判断成功后才开始扫码,扫码尺寸需要匹配XComponent宽高
private areaCallback = Promise_withResolver<Area>()
private loadCallback = Promise_withResolver<boolean>()
private permissionCallback = Promise_withResolver<boolean>()
private checkInitCallback = Promise.all([this.areaCallback.promise, this.loadCallback.promise, this.permissionCallback.promise])
build(){
XComponent({
id: 'componentId',
type: 'surface',
controller: this.mXComponentController
})
.onAreaChange((_, newValue) => {
this.areaCallback.resolve(newValue)
})
.onLoad(() => {
this.loadCallback.resolve(true)
})
.size(FullScreen)
}
aboutToAppear(): void {
this.checkInitCallback.then((value) => {
this.surfaceId = this.mXComponentController.getXComponentSurfaceId();
this.cameraHeight = value[0].height as number
this.cameraWidth = value[0].width as number
if (value[2]) {
this.vm.changeState(SCAN)
} else {
this.vm.changeState(NO_PERMISSION)
}
})
}
在进行页面的初始化时有很多场景触发接口去请求默认数据,相同的请求经常重复发送,所以想起了Synchronize原理,ts中实现如下
export function LazyInit<T>(block: () => Promise<T>) {
const waitQueue: Array<(value: T) => void> = []
let init: boolean | undefined = undefined
let value: T
return () => {
if (init === undefined) {
return new Promise<T>((res, rej) => {
init = false
block().then((value) => {
init = true
res(value)
while (waitQueue.length != 0) {
waitQueue.pop()?.(value)
}
})
})
} else if (init) {
return Promise.resolve(value)
} else {
const resolver = Promise_withResolver<T>()
waitQueue.push(resolver.resolve)
return resolver.promise
}
}
}
直接上场景
waitAndReturn() : Promise<string>{
return new Promise((res) => {
setTimeout(res, 5000, "123")
})
}
private data = LazyInit(async () => {
return await this.waitAndReturn()
})
Logger.debug("gscgsc1", `start`)
this.data().then((value : string) => {
Logger.debug("gscgsc1", `${value}`)
})
this.data().then((value : string) => {
Logger.debug("gscgsc2", `${value}`)
})
this.data().then((value : string) => {
Logger.debug("gscgsc3", `${value}`)
})
this.data().then((value : string) => {
Logger.debug("gscgsc4", `${value}`)
})
this.data().then((value : string) => {
Logger.debug("gscgsc5", `${value}`)
})
运行截图如下
上面的LazyInit返回的是Promise,有时我们需要在全局变量初始化时进行懒加载声明,类似kotlin的by lazy,将上面的功能简化一下如下
export function byLazy<T>(block: () => T): () => T {
let value: T | undefined
return () => {
if (!value) {
value = block()
}
return value
}
}
上才艺
private n = byLazy(() => {
Logger.debug("gscgsc", `math random`)
return Math.random()
})
Logger.debug("gscgsc", 'start')
Logger.debug("gscgsc", `${this.n()}`)
Logger.debug("gscgsc", `${this.n()}`)
Logger.debug("gscgsc", `${this.n()}`)
Logger.debug("gscgsc", 'end')
日志如下