@@ -17,7 +17,6 @@ export type Task = {
1717 error ?: Serialized ;
1818 targetMapId ?: number ;
1919 sourceMapId ?: number ;
20- skipResult ?: boolean ;
2120} ;
2221
2322type PendingResponse = {
@@ -82,18 +81,17 @@ class Actor<Outbox extends MessageMap> {
8281 }
8382
8483 /**
85- * Sends a message from a main-thread map to a Worker or from a Worker back to
86- * a main-thread map instance.
84+ * Sends a message from a main-thread map to a Worker or from a Worker back to a
85+ * main-thread map instance, and resolves with the worker's result. Registers a pending
86+ * response and is cancelable via `signal`. Use {@link Actor#notify} if you don't need a response.
8787 *
8888 * @param type The name of the target method to invoke or '[source-type].[source-name].name' for a method on a WorkerSource.
8989 * @param data The message payload.
90- * @param options Optional send options. When `skipResult: true`, the worker skips posting a response and the call returns void .
90+ * @param options Optional send options (`signal` to cancel, `targetMapId`, scheduler `metadata`) .
9191 * @private
9292 */
93- send < T extends keyof Outbox > ( type : T , data : Outbox [ T ] [ 'params' ] , options : { skipResult : true ; targetMapId ?: number } ) : void ;
94- send < T extends keyof Outbox > ( type : T , data : Outbox [ T ] [ 'params' ] , options ?: { signal ?: AbortSignal ; targetMapId ?: number ; metadata ?: TaskMetadata } ) : Promise < Outbox [ T ] [ 'result' ] > ;
95- send < T extends keyof Outbox > ( type : T , data : Outbox [ T ] [ 'params' ] , options ?: { signal ?: AbortSignal ; targetMapId ?: number ; metadata ?: TaskMetadata ; skipResult ?: boolean } ) : Promise < Outbox [ T ] [ 'result' ] > | void {
96- const { signal, targetMapId, metadata, skipResult = false } = options || { } ;
93+ send < T extends keyof Outbox > ( type : T , data : Outbox [ T ] [ 'params' ] , options ?: { signal ?: AbortSignal ; targetMapId ?: number ; metadata ?: TaskMetadata } ) : Promise < Outbox [ T ] [ 'result' ] > {
94+ const { signal, targetMapId, metadata} = options || { } ;
9795 // We're using a string ID instead of numbers because they are being used as object keys
9896 // anyway, and thus stringified implicitly. We use random IDs because an actor may receive
9997 // message from multiple other actors which could run in different execution context. A
@@ -109,13 +107,10 @@ class Actor<Outbox extends MessageMap> {
109107 id,
110108 type : type as ActorMessage ,
111109 targetMapId,
112- skipResult,
113110 sourceMapId : this . mapId ,
114111 data : serialize ( data , buffers )
115112 } , [ ...buffers ] ) ;
116113
117- if ( skipResult ) return ;
118-
119114 return new Promise ( ( resolve , reject ) => {
120115 const entry : PendingResponse = { resolve, reject, metadata : metadata || DEFAULT_METADATA } ;
121116
@@ -132,6 +127,22 @@ class Actor<Outbox extends MessageMap> {
132127 } ) ;
133128 }
134129
130+ /**
131+ * Sends a message without awaiting for response. Use {@link Actor#send} if you need to await a response.
132+ * @private
133+ */
134+ notify < T extends keyof Outbox > ( type : T , data : Outbox [ T ] [ 'params' ] , options ?: { targetMapId ?: number } ) : void {
135+ const { targetMapId} = options || { } ;
136+ const buffers : Set < Transferable > = new Set ( ) ;
137+
138+ this . target . postMessage ( {
139+ type : type as ActorMessage ,
140+ targetMapId,
141+ sourceMapId : this . mapId ,
142+ data : serialize ( data , buffers )
143+ } , [ ...buffers ] ) ;
144+ }
145+
135146 /**
136147 * Convenience wrapper around {@link send} for the common callback + cancellation pattern:
137148 * fires the message with a fresh AbortController, routes the result to a node-style callback,
@@ -158,12 +169,15 @@ class Actor<Outbox extends MessageMap> {
158169 * must carry the owning map's id as `targetMapId`.
159170 * @private
160171 */
161- getWorkerSourceActor ( mapId : number ) : Pick < Actor < Outbox > , 'send' | 'sendCancelable' | 'scheduler' > {
172+ getWorkerSourceActor ( mapId : number ) : Pick < Actor < Outbox > , 'send' | 'notify' | ' sendCancelable' | 'scheduler' > {
162173 return {
163174 scheduler : this . scheduler ,
164- send : < T extends keyof Outbox > ( type : T , data : Outbox [ T ] [ 'params' ] , options ?: { signal ?: AbortSignal ; metadata ?: TaskMetadata ; skipResult ?: boolean } ) => {
175+ send : < T extends keyof Outbox > ( type : T , data : Outbox [ T ] [ 'params' ] , options ?: { signal ?: AbortSignal ; metadata ?: TaskMetadata } ) => {
165176 return this . send ( type , data , { ...options , targetMapId : mapId } ) ;
166177 } ,
178+ notify : < T extends keyof Outbox > ( type : T , data : Outbox [ T ] [ 'params' ] ) => {
179+ this . notify ( type , data , { targetMapId : mapId } ) ;
180+ } ,
167181 sendCancelable : < T extends keyof Outbox > ( type : T , data : Outbox [ T ] [ 'params' ] , options : { metadata ?: TaskMetadata } , callback : ( err ?: Error | null , result ?: Outbox [ T ] [ 'result' ] ) => void ) => {
168182 return this . sendCancelable ( type , data , { ...options , targetMapId : mapId } , callback ) ;
169183 } ,
@@ -175,8 +189,6 @@ class Actor<Outbox extends MessageMap> {
175189 if ( ! data ) return ;
176190
177191 const id = data . id ;
178- if ( ! id ) return ;
179-
180192 if ( data . targetMapId && this . mapId !== data . targetMapId ) {
181193 return ;
182194 }
@@ -221,47 +233,51 @@ class Actor<Outbox extends MessageMap> {
221233 entry . reject ( err as Error ) ;
222234 }
223235 }
224- } else {
225- const buffers : Set < Transferable > = new Set ( ) ;
226- const params = deserialize ( task . data ) ;
227236
228- // `task.type` is a message name ('loadTile', etc.) or a runtime
229- // `sourcetype.method` (WorkerSource types register via Map#addSourceType).
230- // Both dispatch by runtime string, so the handler lookup is untyped.
231- try {
232- let result : unknown ;
233- if ( this . parent [ task . type ] ) {
234- // task.type == 'loadTile', 'removeTile', etc.
235- result = await this . parent [ task . type ] ( task . sourceMapId , params ) ;
236- } else if ( this . parent . getWorkerSource ) {
237- // task.type == sourcetype.method
238- const keys = task . type . split ( '.' ) ;
239- const { source, scope} = params as { source : string ; scope : string } ;
240- const workerSource = this . parent . getWorkerSource ( task . sourceMapId , { type : keys [ 0 ] , source, scope, uid : 0 } ) ;
241- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
242- result = await workerSource [ keys [ 1 ] ] ( params ) ;
243- } else {
244- throw new Error ( `Could not find function ${ task . type } ` ) ;
245- }
246- if ( ! task . skipResult ) {
247- this . target . postMessage ( {
248- id,
249- type : '<response>' ,
250- sourceMapId : this . mapId ,
251- error : null ,
252- data : serialize ( result , buffers )
253- } , [ ...buffers ] ) ;
254- }
255- } catch ( err ) {
256- assert ( ! task . skipResult , 'Tasks that skip results should not throw errors' ) ;
257- this . target . postMessage ( {
258- id,
259- type : '<response>' ,
260- sourceMapId : this . mapId ,
261- error : serialize ( err ) ,
262- data : null
263- } , [ ] ) ;
237+ return ;
238+ }
239+
240+ const buffers : Set < Transferable > = new Set ( ) ;
241+ const params = deserialize ( task . data ) ;
242+
243+ // `task.type` is a message name ('loadTile', etc.) or a runtime
244+ // `sourcetype.method` (WorkerSource types register via Map#addSourceType).
245+ // Both dispatch by runtime string, so the handler lookup is untyped.
246+ try {
247+ let result : unknown ;
248+ if ( this . parent [ task . type ] ) {
249+ // task.type == 'loadTile', 'removeTile', etc.
250+ result = await this . parent [ task . type ] ( task . sourceMapId , params ) ;
251+ } else if ( this . parent . getWorkerSource ) {
252+ // task.type == sourcetype.method
253+ const keys = task . type . split ( '.' ) ;
254+ const { source, scope} = params as { source : string ; scope : string } ;
255+ const workerSource = this . parent . getWorkerSource ( task . sourceMapId , { type : keys [ 0 ] , source, scope, uid : 0 } ) ;
256+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
257+ result = await workerSource [ keys [ 1 ] ] ( params ) ;
258+ } else {
259+ throw new Error ( `Could not find function ${ task . type } ` ) ;
264260 }
261+
262+ if ( ! id ) return ;
263+
264+ this . target . postMessage ( {
265+ id,
266+ type : '<response>' ,
267+ sourceMapId : this . mapId ,
268+ error : null ,
269+ data : serialize ( result , buffers )
270+ } , [ ...buffers ] ) ;
271+ } catch ( err ) {
272+ if ( ! id ) assert ( false , `"${ task . type } " threw: ${ ( err as Error ) . message } ` ) ;
273+
274+ this . target . postMessage ( {
275+ id,
276+ type : '<response>' ,
277+ sourceMapId : this . mapId ,
278+ error : serialize ( err ) ,
279+ data : null
280+ } , [ ] ) ;
265281 }
266282 }
267283
0 commit comments