@@ -28,6 +28,12 @@ const {
28
28
SymbolToPrimitive
29
29
} = primordials ;
30
30
31
+ const {
32
+ codes : { ERR_INVALID_ARG_TYPE }
33
+ } = require ( 'internal/errors' ) ;
34
+
35
+ let DOMException ;
36
+
31
37
const {
32
38
immediateInfo,
33
39
toggleImmediateRef
@@ -129,6 +135,11 @@ function enroll(item, msecs) {
129
135
* DOM-style timers
130
136
*/
131
137
138
+ function lazyDOMException ( message ) {
139
+ if ( DOMException === undefined )
140
+ DOMException = internalBinding ( 'messaging' ) . DOMException ;
141
+ return new DOMException ( message ) ;
142
+ }
132
143
133
144
function setTimeout ( callback , after , arg1 , arg2 , arg3 ) {
134
145
validateCallback ( callback ) ;
@@ -160,11 +171,40 @@ function setTimeout(callback, after, arg1, arg2, arg3) {
160
171
return timeout ;
161
172
}
162
173
163
- setTimeout [ customPromisify ] = function ( after , value ) {
174
+ setTimeout [ customPromisify ] = function ( after , value , options = { } ) {
164
175
const args = value !== undefined ? [ value ] : value ;
165
- return new Promise ( ( resolve ) => {
176
+ if ( options == null || typeof options !== 'object' ) {
177
+ return Promise . reject (
178
+ new ERR_INVALID_ARG_TYPE (
179
+ 'options' ,
180
+ 'Object' ,
181
+ options ) ) ;
182
+ }
183
+ const { signal } = options ;
184
+ if ( signal !== undefined &&
185
+ ( signal === null ||
186
+ typeof signal !== 'object' ||
187
+ ! ( 'aborted' in signal ) ) ) {
188
+ return Promise . reject (
189
+ new ERR_INVALID_ARG_TYPE (
190
+ 'options.signal' ,
191
+ 'AbortSignal' ,
192
+ signal ) ) ;
193
+ }
194
+ // TODO(@jasnell): If a decision is made that this cannot be backported
195
+ // to 12.x, then this can be converted to use optional chaining to
196
+ // simplify the check.
197
+ if ( signal && signal . aborted )
198
+ return Promise . reject ( lazyDOMException ( 'AbortError' ) ) ;
199
+ return new Promise ( ( resolve , reject ) => {
166
200
const timeout = new Timeout ( resolve , after , args , false , true ) ;
167
201
insert ( timeout , timeout . _idleTimeout ) ;
202
+ if ( signal ) {
203
+ signal . addEventListener ( 'abort' , ( ) => {
204
+ clearTimeout ( timeout ) ;
205
+ reject ( lazyDOMException ( 'AbortError' ) ) ;
206
+ } , { once : true } ) ;
207
+ }
168
208
} ) ;
169
209
} ;
170
210
@@ -300,8 +340,39 @@ function setImmediate(callback, arg1, arg2, arg3) {
300
340
return new Immediate ( callback , args ) ;
301
341
}
302
342
303
- setImmediate [ customPromisify ] = function ( value ) {
304
- return new Promise ( ( resolve ) => new Immediate ( resolve , [ value ] ) ) ;
343
+ setImmediate [ customPromisify ] = function ( value , options = { } ) {
344
+ if ( options == null || typeof options !== 'object' ) {
345
+ return Promise . reject (
346
+ new ERR_INVALID_ARG_TYPE (
347
+ 'options' ,
348
+ 'Object' ,
349
+ options ) ) ;
350
+ }
351
+ const { signal } = options ;
352
+ if ( signal !== undefined &&
353
+ ( signal === null ||
354
+ typeof signal !== 'object' ||
355
+ ! ( 'aborted' in signal ) ) ) {
356
+ return Promise . reject (
357
+ new ERR_INVALID_ARG_TYPE (
358
+ 'options.signal' ,
359
+ 'AbortSignal' ,
360
+ signal ) ) ;
361
+ }
362
+ // TODO(@jasnell): If a decision is made that this cannot be backported
363
+ // to 12.x, then this can be converted to use optional chaining to
364
+ // simplify the check.
365
+ if ( signal && signal . aborted )
366
+ return Promise . reject ( lazyDOMException ( 'AbortError' ) ) ;
367
+ return new Promise ( ( resolve , reject ) => {
368
+ const immediate = new Immediate ( resolve , [ value ] ) ;
369
+ if ( signal ) {
370
+ signal . addEventListener ( 'abort' , ( ) => {
371
+ clearImmediate ( immediate ) ;
372
+ reject ( lazyDOMException ( 'AbortError' ) ) ;
373
+ } , { once : true } ) ;
374
+ }
375
+ } ) ;
305
376
} ;
306
377
307
378
function clearImmediate ( immediate ) {
0 commit comments