@@ -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 )
@@ -172,7 +196,68 @@ class AbortSignal extends EventTarget {
172
196
timeOutSignals . delete ( this ) ;
173
197
}
174
198
}
199
+
200
+ [ kTransfer ] ( ) {
201
+ validateAbortSignal ( this ) ;
202
+ const aborted = this . aborted ;
203
+ if ( aborted ) {
204
+ const reason = this . reason ;
205
+ return {
206
+ data : { aborted, reason } ,
207
+ deserializeInfo : 'internal/abort_controller:ClonedAbortSignal' ,
208
+ } ;
209
+ }
210
+
211
+ const { port1, port2 } = this [ kCloneData ] ;
212
+ this [ kCloneData ] = undefined ;
213
+
214
+ this . addEventListener ( 'abort' , ( ) => {
215
+ port1 . postMessage ( this . reason ) ;
216
+ port1 . close ( ) ;
217
+ } , { once : true } ) ;
218
+
219
+ return {
220
+ data : { port : port2 } ,
221
+ deserializeInfo : 'internal/abort_controller:ClonedAbortSignal' ,
222
+ } ;
223
+ }
224
+
225
+ [ kTransferList ] ( ) {
226
+ if ( ! this . aborted ) {
227
+ const { port1, port2 } = lazyMessageChannel ( ) ;
228
+ port1 . unref ( ) ;
229
+ port2 . unref ( ) ;
230
+ this [ kCloneData ] = {
231
+ port1,
232
+ port2,
233
+ } ;
234
+ return [ port2 ] ;
235
+ }
236
+ return [ ] ;
237
+ }
238
+
239
+ [ kDeserialize ] ( { aborted, reason, port } ) {
240
+ if ( aborted ) {
241
+ this [ kAborted ] = aborted ;
242
+ this [ kReason ] = reason ;
243
+ return ;
244
+ }
245
+
246
+ port . onmessage = ( { data } ) => {
247
+ abortSignal ( this , data ) ;
248
+ port . close ( ) ;
249
+ port . onmessage = undefined ;
250
+ } ;
251
+ // The receiving port, by itself, should never keep the event loop open.
252
+ // The unref() has to be called *after* setting the onmessage handler.
253
+ port . unref ( ) ;
254
+ }
255
+ }
256
+
257
+ function ClonedAbortSignal ( ) {
258
+ return createAbortSignal ( ) ;
175
259
}
260
+ ClonedAbortSignal . prototype [ kDeserialize ] = ( ) => { } ;
176
261
177
262
ObjectDefineProperties ( AbortSignal . prototype , {
178
263
aborted : { enumerable : true }
@@ -192,7 +277,7 @@ function createAbortSignal(aborted = false, reason = undefined) {
192
277
ObjectSetPrototypeOf ( signal , AbortSignal . prototype ) ;
193
278
signal [ kAborted ] = aborted ;
194
279
signal [ kReason ] = reason ;
195
- return signal ;
280
+ return lazyMakeTransferable ( signal ) ;
196
281
}
197
282
198
283
function abortSignal ( signal , reason ) {
@@ -259,4 +344,5 @@ module.exports = {
259
344
kAborted,
260
345
AbortController,
261
346
AbortSignal,
347
+ ClonedAbortSignal,
262
348
} ;
0 commit comments