Skip to content

Commit

Permalink
feat: 更新 WorkerHelper
Browse files Browse the repository at this point in the history
  • Loading branch information
stupidZhu committed Dec 6, 2023
1 parent 2aa2c16 commit a625bda
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 25 deletions.
26 changes: 21 additions & 5 deletions apps/web-visualization-demos/src/page/cesiumPage/worker.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
import { WorkerHelper } from "@zxtool/utils"
import { WorkerFn, WorkerHelper } from "@zxtool/utils"

function work() {
onmessage = ({ data: { key, message } }) => {
postMessage({ key, result: `result is ${message}` })
const work: WorkerFn<string> = getWorkerUtil => {
onmessage = e => {
const { getMsg, postMsg, throwError } = getWorkerUtil(e)
const message = getMsg()
if (message === "hello 2") throwError(`error is ${message}`)
else postMsg(`result is ${message}`)
}
}

const workerHelper = new WorkerHelper(work)

workerHelper.postMessage("hello world").then(console.log)
workerHelper
.postMessage<string>("hello 1")
.then(res => {
console.log(res)
})
.catch(err => {
console.error(err)
})
workerHelper.postMessage("hello 2").then(console.log).catch(console.error)
workerHelper.postMessage("hello 3").then(console.log).catch(console.error)
setTimeout(() => {
workerHelper.terminate()
workerHelper.postMessage("hello 4").then(console.log).catch(console.error)
}, 1000)
14 changes: 14 additions & 0 deletions packages/zxtool-utils/src/type/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,18 @@ export type Merge<T> = {
}
export type PartialByKeys<O, K extends keyof O> = Merge<Partial<O> & Omit<O, K>>

// interface RejectedPromise<E> {
// reject(reason: E): void
// }

// declare module "PromiseConstructor" {
// interface PromiseConstructor {
// reject<E = any>(reason?: E): Promise<T>
// }
// }

interface Promise<T, E> extends Promise<T> {
reject<E = any>(reason?: E): Promise<T>
}

export as namespace ZU
12 changes: 6 additions & 6 deletions packages/zxtool-utils/src/widget/EmitterHelper/EmitterHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { REST } from "../../type"
import { genZUInfo } from "../../util"
import { CommonUtil, GetNumberProps } from "../CommonUtil/CommonUtil"

const genEmitterInfo = genZUInfo("EmitterHelper")
const genInfo = genZUInfo("EmitterHelper")

export type EmitterHandler<T extends REST = REST> = ((...rest: T) => void) & { _raw?: (...rest: T) => void }
export type OverflowStrategy = "prevent" | "shift"
Expand Down Expand Up @@ -134,15 +134,15 @@ export class EmitterHelper {
}
if (handlers.length >= this.maxCount.handler) {
if (this.overflowStrategy.handler === "prevent") {
throw new Error(genEmitterInfo("on 调用失败, handler 数量已达到上限"))
throw new Error(genInfo("on 调用失败, handler 数量已达到上限"))
}
console.warn(genEmitterInfo(`key 为 ${String(key)} 的第一个 handler 已被移除`))
console.warn(genInfo(`key 为 ${String(key)} 的第一个 handler 已被移除`))
handlers.shift()
handlers.push(value as EmitterHandler)
return
}
} else {
if (key === "*") throw new Error(genEmitterInfo("emit 调用失败, key 不允许为 *"))
if (key === "*") throw new Error(genInfo("emit 调用失败, key 不允许为 *"))
const history = this.historyCollection.get(key)
if (!history) {
this.historyCollection.set(key, [value as REST])
Expand All @@ -154,9 +154,9 @@ export class EmitterHelper {
}
if (history.length >= this.maxCount.history) {
if (this.overflowStrategy.history === "prevent") {
throw new Error(genEmitterInfo("emit 调用失败, history 数量已达到上限"))
throw new Error(genInfo("emit 调用失败, history 数量已达到上限"))
}
console.warn(genEmitterInfo(`key 为 ${String(key)} 的第一条 history 已被移除`))
console.warn(genInfo(`key 为 ${String(key)} 的第一条 history 已被移除`))
history.shift()
history.push(value as REST)
return
Expand Down
75 changes: 61 additions & 14 deletions packages/zxtool-utils/src/widget/WorkerHelper/WorkerHelper.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,76 @@
// https://zhuanlan.zhihu.com/p/83001302

import { nanoid } from "nanoid"
import { genZUInfo } from "../../util"
import { CommonUtil } from "../CommonUtil/CommonUtil"

const genInfo = genZUInfo("WorkerHelper")

function getWorkerUtil<M, R>(e: MessageEvent<{ key: number; message: M }>) {
const { key, message } = e.data
return {
getMsg() {
return message
},
postMsg(message: R) {
postMessage({ key, message })
},
throwError(message: R) {
throw new Error(JSON.stringify({ key, message }))
},
}
}

export type GetWorkerUtilType<M = unknown, R = unknown> = (e: MessageEvent<{ key: number; message: M }>) => {
getMsg(): M
postMsg(message: R): void
throwError(message: R): never
}

export type WorkerFn<T = unknown> = (getWorkerUtil: GetWorkerUtilType<T>) => void

export class WorkerHelper {
worker: Worker
jobMap: Map<PropertyKey, Function> = new Map()
private worker: Worker | null = null
private jobMap: Map<PropertyKey, Function[]> = new Map()
private key = 0

static fn2url(fn: Function) {
return URL.createObjectURL(new Blob([`(${fn.toString()})()`]))
static fn2url(fn: WorkerFn) {
return URL.createObjectURL(new Blob([`(${fn.toString()})(${getWorkerUtil.toString()})`]))
}

constructor(fn: Function) {
constructor(fn: WorkerFn<any>) {
this.worker = new Worker(WorkerHelper.fn2url(fn))

this.worker.onmessage = ({ data: { result, key } }) => {
this.jobMap.get(key)?.(result)
this.jobMap.delete(key)
this.worker.onmessage = ({ data }) => {
if ("message" in data && "key" in data) {
const { message, key } = data
this.jobMap.get(key)?.[0]?.(message)
this.jobMap.delete(key)
}
}

this.worker.onerror = e => {
e.preventDefault()
const data = CommonUtil.parseJson<{ key: number; message: unknown }>(e.message.replace("Uncaught Error: ", ""))
if (data && "message" in data && "key" in data) {
const { message, key } = data
this.jobMap.get(key)?.[1]?.(message)
this.jobMap.delete(key)
}
}
}

postMessage(message: any) {
return new Promise(resolve => {
const key = nanoid()
this.jobMap.set(key, resolve)
this.worker.postMessage({ key, message })
postMessage<T>(message: unknown) {
if (!this.worker) throw new Error(genInfo("worker 没有初始化或者已经销毁"))

return new Promise<T>((resolve, reject) => {
const key = this.key++
this.jobMap.set(key, [resolve, reject])
this.worker!.postMessage({ key, message })
})
}

terminate() {
this.worker?.terminate()
this.worker = null
}
}

0 comments on commit a625bda

Please sign in to comment.