@@ -47,13 +47,37 @@ const {
47
47
setTimeout,
48
48
} = require ( 'timers' ) ;
49
49
50
- const kAborted = Symbol ( 'kAborted' ) ;
51
- const kReason = Symbol ( 'kReason' ) ;
52
- const kTimeout = Symbol ( 'kTimeout' ) ;
50
+ const {
51
+ messaging_deserialize_symbol : kDeserialize ,
52
+ messaging_transfer_symbol : kTransfer ,
53
+ messaging_transfer_list_symbol : kTransferList
54
+ } = internalBinding ( 'symbols' ) ;
53
55
54
- const timeOutSignals = new SafeSet ( ) ;
56
+ let _MessageChannel ;
57
+ let makeTransferable ;
58
+
59
+ // Loading the MessageChannel and makeTransferable have to be done lazily
60
+ // because otherwise we'll end up with a require cycle that ends up with
61
+ // an incomplete initialization of abort_controller.
62
+
63
+ function lazyMessageChannel ( ) {
64
+ _MessageChannel ??= require ( 'internal/worker/io' ) . MessageChannel ;
65
+ return new _MessageChannel ( ) ;
66
+ }
67
+
68
+ function lazyMakeTransferable ( obj ) {
69
+ makeTransferable ??=
70
+ require ( 'internal/worker/js_transferable' ) . makeTransferable ;
71
+ return makeTransferable ( obj ) ;
72
+ }
55
73
56
74
const clearTimeoutRegistry = new SafeFinalizationRegistry ( clearTimeout ) ;
75
+ const timeOutSignals = new SafeSet ( ) ;
76
+
77
+ const kAborted = Symbol ( 'kAborted' ) ;
78
+ const kReason = Symbol ( 'kReason' ) ;
79
+ const kCloneData = Symbol ( 'kCloneData' ) ;
80
+ const kTimeout = Symbol ( 'kTimeout' ) ;
57
81
58
82
function customInspect ( self , obj , depth , options ) {
59
83
if ( depth < 0 )
@@ -165,7 +189,68 @@ class AbortSignal extends EventTarget {
165
189
timeOutSignals . delete ( this ) ;
166
190
}
167
191
}
192
+
193
+ [ kTransfer ] ( ) {
194
+ validateAbortSignal ( this ) ;
195
+ const aborted = this . aborted ;
196
+ if ( aborted ) {
197
+ const reason = this . reason ;
198
+ return {
199
+ data : { aborted, reason } ,
200
+ deserializeInfo : 'internal/abort_controller:ClonedAbortSignal' ,
201
+ } ;
202
+ }
203
+
204
+ const { port1, port2 } = this [ kCloneData ] ;
205
+ this [ kCloneData ] = undefined ;
206
+
207
+ this . addEventListener ( 'abort' , ( ) => {
208
+ port1 . postMessage ( this . reason ) ;
209
+ port1 . close ( ) ;
210
+ } , { once : true } ) ;
211
+
212
+ return {
213
+ data : { port : port2 } ,
214
+ deserializeInfo : 'internal/abort_controller:ClonedAbortSignal' ,
215
+ } ;
216
+ }
217
+
218
+ [ kTransferList ] ( ) {
219
+ if ( ! this . aborted ) {
220
+ const { port1, port2 } = lazyMessageChannel ( ) ;
221
+ port1 . unref ( ) ;
222
+ port2 . unref ( ) ;
223
+ this [ kCloneData ] = {
224
+ port1,
225
+ port2,
226
+ } ;
227
+ return [ port2 ] ;
228
+ }
229
+ return [ ] ;
230
+ }
231
+
232
+ [ kDeserialize ] ( { aborted, reason, port } ) {
233
+ if ( aborted ) {
234
+ this [ kAborted ] = aborted ;
235
+ this [ kReason ] = reason ;
236
+ return ;
237
+ }
238
+
239
+ port . onmessage = ( { data } ) => {
240
+ abortSignal ( this , data ) ;
241
+ port . close ( ) ;
242
+ port . onmessage = undefined ;
243
+ } ;
244
+ // The receiving port, by itself, should never keep the event loop open.
245
+ // The unref() has to be called *after* setting the onmessage handler.
246
+ port . unref ( ) ;
247
+ }
248
+ }
249
+
250
+ function ClonedAbortSignal ( ) {
251
+ return createAbortSignal ( ) ;
168
252
}
253
+ ClonedAbortSignal . prototype [ kDeserialize ] = ( ) => { } ;
169
254
170
255
ObjectDefineProperties ( AbortSignal . prototype , {
171
256
aborted : { enumerable : true }
@@ -185,7 +270,7 @@ function createAbortSignal(aborted = false, reason = undefined) {
185
270
ObjectSetPrototypeOf ( signal , AbortSignal . prototype ) ;
186
271
signal [ kAborted ] = aborted ;
187
272
signal [ kReason ] = reason ;
188
- return signal ;
273
+ return lazyMakeTransferable ( signal ) ;
189
274
}
190
275
191
276
function abortSignal ( signal , reason ) {
@@ -252,4 +337,5 @@ module.exports = {
252
337
kAborted,
253
338
AbortController,
254
339
AbortSignal,
340
+ ClonedAbortSignal,
255
341
} ;
0 commit comments