@@ -26,6 +26,12 @@ const {
26
26
Promise,
27
27
} = primordials ;
28
28
29
+ const {
30
+ codes : { ERR_INVALID_ARG_TYPE }
31
+ } = require ( 'internal/errors' ) ;
32
+
33
+ let DOMException ;
34
+
29
35
const {
30
36
immediateInfo,
31
37
toggleImmediateRef
@@ -118,6 +124,11 @@ function enroll(item, msecs) {
118
124
* DOM-style timers
119
125
*/
120
126
127
+ function lazyDOMException ( message ) {
128
+ if ( DOMException === undefined )
129
+ DOMException = internalBinding ( 'messaging' ) . DOMException ;
130
+ return new DOMException ( message ) ;
131
+ }
121
132
122
133
function setTimeout ( callback , after , arg1 , arg2 , arg3 ) {
123
134
validateCallback ( callback ) ;
@@ -149,11 +160,40 @@ function setTimeout(callback, after, arg1, arg2, arg3) {
149
160
return timeout ;
150
161
}
151
162
152
- setTimeout [ customPromisify ] = function ( after , value ) {
163
+ setTimeout [ customPromisify ] = function ( after , value , options = { } ) {
153
164
const args = value !== undefined ? [ value ] : value ;
154
- return new Promise ( ( resolve ) => {
165
+ if ( options == null || typeof options !== 'object' ) {
166
+ return Promise . reject (
167
+ new ERR_INVALID_ARG_TYPE (
168
+ 'options' ,
169
+ 'Object' ,
170
+ options ) ) ;
171
+ }
172
+ const { signal } = options ;
173
+ if ( signal !== undefined &&
174
+ ( signal === null ||
175
+ typeof signal !== 'object' ||
176
+ ! ( 'aborted' in signal ) ) ) {
177
+ return Promise . reject (
178
+ new ERR_INVALID_ARG_TYPE (
179
+ 'options.signal' ,
180
+ 'AbortSignal' ,
181
+ signal ) ) ;
182
+ }
183
+ // TODO(@jasnell): If a decision is made that this cannot be backported
184
+ // to 12.x, then this can be converted to use optional chaining to
185
+ // simplify the check.
186
+ if ( signal && signal . aborted )
187
+ return Promise . reject ( lazyDOMException ( 'AbortError' ) ) ;
188
+ return new Promise ( ( resolve , reject ) => {
155
189
const timeout = new Timeout ( resolve , after , args , false , true ) ;
156
190
insert ( timeout , timeout . _idleTimeout ) ;
191
+ if ( signal ) {
192
+ signal . addEventListener ( 'abort' , ( ) => {
193
+ clearTimeout ( timeout ) ;
194
+ reject ( lazyDOMException ( 'AbortError' ) ) ;
195
+ } , { once : true } ) ;
196
+ }
157
197
} ) ;
158
198
} ;
159
199
@@ -272,8 +312,39 @@ function setImmediate(callback, arg1, arg2, arg3) {
272
312
return new Immediate ( callback , args ) ;
273
313
}
274
314
275
- setImmediate [ customPromisify ] = function ( value ) {
276
- return new Promise ( ( resolve ) => new Immediate ( resolve , [ value ] ) ) ;
315
+ setImmediate [ customPromisify ] = function ( value , options = { } ) {
316
+ if ( options == null || typeof options !== 'object' ) {
317
+ return Promise . reject (
318
+ new ERR_INVALID_ARG_TYPE (
319
+ 'options' ,
320
+ 'Object' ,
321
+ options ) ) ;
322
+ }
323
+ const { signal } = options ;
324
+ if ( signal !== undefined &&
325
+ ( signal === null ||
326
+ typeof signal !== 'object' ||
327
+ ! ( 'aborted' in signal ) ) ) {
328
+ return Promise . reject (
329
+ new ERR_INVALID_ARG_TYPE (
330
+ 'options.signal' ,
331
+ 'AbortSignal' ,
332
+ signal ) ) ;
333
+ }
334
+ // TODO(@jasnell): If a decision is made that this cannot be backported
335
+ // to 12.x, then this can be converted to use optional chaining to
336
+ // simplify the check.
337
+ if ( signal && signal . aborted )
338
+ return Promise . reject ( lazyDOMException ( 'AbortError' ) ) ;
339
+ return new Promise ( ( resolve , reject ) => {
340
+ const immediate = new Immediate ( resolve , [ value ] ) ;
341
+ if ( signal ) {
342
+ signal . addEventListener ( 'abort' , ( ) => {
343
+ clearImmediate ( immediate ) ;
344
+ reject ( lazyDOMException ( 'AbortError' ) ) ;
345
+ } , { once : true } ) ;
346
+ }
347
+ } ) ;
277
348
} ;
278
349
279
350
function clearImmediate ( immediate ) {
0 commit comments