@@ -15,10 +15,12 @@ const timerPromises = require('timers/promises');
1515
1616const setTimeout = promisify ( timers . setTimeout ) ;
1717const setImmediate = promisify ( timers . setImmediate ) ;
18+ const setInterval = promisify ( timers . setInterval ) ;
1819const exec = promisify ( child_process . exec ) ;
1920
2021assert . strictEqual ( setTimeout , timerPromises . setTimeout ) ;
2122assert . strictEqual ( setImmediate , timerPromises . setImmediate ) ;
23+ assert . strictEqual ( setInterval , timerPromises . setInterval ) ;
2224
2325process . on ( 'multipleResolves' , common . mustNotCall ( ) ) ;
2426
@@ -50,48 +52,159 @@ process.on('multipleResolves', common.mustNotCall());
5052 } ) ) ;
5153}
5254
55+ {
56+ const controller = new AbortController ( ) ;
57+ const { signal } = controller ;
58+ const iterable = setInterval ( 1 , undefined , { signal } ) ;
59+ const iterator = iterable [ Symbol . asyncIterator ] ( ) ;
60+ const promise = iterator . next ( ) ;
61+ promise . then ( common . mustCall ( ( result ) => {
62+ assert . ok ( ! result . done ) ;
63+ assert . strictEqual ( result . value , undefined ) ;
64+ controller . abort ( ) ;
65+ return assert . rejects ( iterator . next ( ) , / A b o r t E r r o r / ) ;
66+ } ) ) . then ( common . mustCall ( ) ) ;
67+ }
68+
69+ {
70+ const controller = new AbortController ( ) ;
71+ const { signal } = controller ;
72+ const iterable = setInterval ( 1 , undefined , { signal, throwOnAbort : false } ) ;
73+ const iterator = iterable [ Symbol . asyncIterator ] ( ) ;
74+ const promise = iterator . next ( ) ;
75+ promise . then ( common . mustCall ( ( result ) => {
76+ assert . ok ( ! result . done ) ;
77+ assert . strictEqual ( result . value , undefined ) ;
78+ controller . abort ( ) ;
79+ return iterator . next ( ) ;
80+ } ) ) . then ( common . mustCall ( ( result ) => {
81+ assert . ok ( result . done ) ;
82+ } ) ) ;
83+ }
84+
85+ {
86+ const controller = new AbortController ( ) ;
87+ const { signal } = controller ;
88+ const iterable = setInterval ( 1 , 'foobar' , { signal } ) ;
89+ const iterator = iterable [ Symbol . asyncIterator ] ( ) ;
90+ const promise = iterator . next ( ) ;
91+ promise . then ( common . mustCall ( ( result ) => {
92+ assert . ok ( ! result . done ) ;
93+ assert . strictEqual ( result . value , 'foobar' ) ;
94+ controller . abort ( ) ;
95+ return assert . rejects ( iterator . next ( ) , / A b o r t E r r o r / ) ;
96+ } ) ) . then ( common . mustCall ( ) ) ;
97+ }
98+
99+ {
100+ const controller = new AbortController ( ) ;
101+ const { signal } = controller ;
102+ const iterable = setInterval ( 1 , 'foobar' , { signal, throwOnAbort : false } ) ;
103+ const iterator = iterable [ Symbol . asyncIterator ] ( ) ;
104+ const promise = iterator . next ( ) ;
105+ promise . then ( common . mustCall ( ( result ) => {
106+ assert . ok ( ! result . done ) ;
107+ assert . strictEqual ( result . value , 'foobar' ) ;
108+ controller . abort ( ) ;
109+ return iterator . next ( ) ;
110+ } ) ) . then ( common . mustCall ( ( result ) => {
111+ assert . ok ( result . done ) ;
112+ } ) ) ;
113+ }
114+
53115{
54116 const ac = new AbortController ( ) ;
55117 const signal = ac . signal ;
56- assert . rejects ( setTimeout ( 10 , undefined , { signal } ) , / A b o r t E r r o r / ) ;
118+ assert . rejects ( setTimeout ( 10 , undefined , { signal } ) , / A b o r t E r r o r / )
119+ . then ( common . mustCall ( ) ) ;
57120 ac . abort ( ) ;
58121}
59122
60123{
61124 const ac = new AbortController ( ) ;
62125 const signal = ac . signal ;
63126 ac . abort ( ) ; // Abort in advance
64- assert . rejects ( setTimeout ( 10 , undefined , { signal } ) , / A b o r t E r r o r / ) ;
127+ assert . rejects ( setTimeout ( 10 , undefined , { signal } ) , / A b o r t E r r o r / )
128+ . then ( common . mustCall ( ) ) ;
65129}
66130
67131{
68132 const ac = new AbortController ( ) ;
69133 const signal = ac . signal ;
70- assert . rejects ( setImmediate ( 10 , { signal } ) , / A b o r t E r r o r / ) ;
134+ assert . rejects ( setImmediate ( 10 , { signal } ) , / A b o r t E r r o r / )
135+ . then ( common . mustCall ( ) ) ;
71136 ac . abort ( ) ;
72137}
73138
74139{
75140 const ac = new AbortController ( ) ;
76141 const signal = ac . signal ;
77142 ac . abort ( ) ; // Abort in advance
78- assert . rejects ( setImmediate ( 10 , { signal } ) , / A b o r t E r r o r / ) ;
143+ assert . rejects ( setImmediate ( 10 , { signal } ) , / A b o r t E r r o r / )
144+ . then ( common . mustCall ( ) ) ;
145+ }
146+
147+ {
148+ const ac = new AbortController ( ) ;
149+ const { signal } = ac ;
150+ ac . abort ( ) ; // Abort in advance
151+
152+ const iterable = setInterval ( 1 , undefined , { signal } ) ;
153+ const iterator = iterable [ Symbol . asyncIterator ] ( ) ;
154+ assert . rejects ( iterator . next ( ) , / A b o r t E r r o r / ) . then ( common . mustCall ( ) ) ;
155+ }
156+
157+ {
158+ const ac = new AbortController ( ) ;
159+ const { signal } = ac ;
160+
161+ const iterable = setInterval ( 100 , undefined , { signal } ) ;
162+ const iterator = iterable [ Symbol . asyncIterator ] ( ) ;
163+
164+ // This promise should take 100 seconds to resolve, so now aborting it should
165+ // mean we abort early
166+ const promise = iterator . next ( ) ;
167+
168+ ac . abort ( ) ; // Abort in after we have a next promise
169+
170+ assert . rejects ( promise , / A b o r t E r r o r / ) . then ( common . mustCall ( ) ) ;
79171}
80172
81173{
82174 // Check that aborting after resolve will not reject.
83175 const ac = new AbortController ( ) ;
84176 const signal = ac . signal ;
85- setTimeout ( 10 , undefined , { signal } ) . then ( ( ) => {
86- ac . abort ( ) ;
87- } ) ;
177+ assert . doesNotReject ( setTimeout ( 10 , undefined , { signal } )
178+ . then ( common . mustCall ( ( ) => {
179+ ac . abort ( ) ;
180+ } ) ) ) . then ( common . mustCall ( ) ) ;
88181}
89182{
90183 // Check that aborting after resolve will not reject.
91184 const ac = new AbortController ( ) ;
92185 const signal = ac . signal ;
93- setImmediate ( 10 , { signal } ) . then ( ( ) => {
186+ assert . doesNotReject ( setImmediate ( 10 , { signal } ) . then ( common . mustCall ( ( ) => {
94187 ac . abort ( ) ;
188+ } ) ) ) . then ( common . mustCall ( ) ) ;
189+ }
190+
191+ {
192+ [ 1 , '' , Infinity , null , { } ] . forEach ( ( ref ) => {
193+ const iterable = setInterval ( 10 , undefined , { ref } ) ;
194+ assert . rejects ( ( ) => iterable [ Symbol . asyncIterator ] ( ) . next ( ) , / E R R _ I N V A L I D _ A R G _ T Y P E / )
195+ . then ( common . mustCall ( ) ) ;
196+ } ) ;
197+
198+ [ 1 , '' , Infinity , null , { } ] . forEach ( ( signal ) => {
199+ const iterable = setInterval ( 10 , undefined , { signal } ) ;
200+ assert . rejects ( ( ) => iterable [ Symbol . asyncIterator ] ( ) . next ( ) , / E R R _ I N V A L I D _ A R G _ T Y P E / )
201+ . then ( common . mustCall ( ) ) ;
202+ } ) ;
203+
204+ [ 1 , '' , Infinity , null , true , false ] . forEach ( ( options ) => {
205+ const iterable = setInterval ( 10 , undefined , options ) ;
206+ assert . rejects ( ( ) => iterable [ Symbol . asyncIterator ] ( ) . next ( ) , / E R R _ I N V A L I D _ A R G _ T Y P E / )
207+ . then ( common . mustCall ( ) ) ;
95208 } ) ;
96209}
97210
@@ -165,3 +278,87 @@ process.on('multipleResolves', common.mustNotCall());
165278 assert . strictEqual ( stderr , '' ) ;
166279 } ) ) ;
167280}
281+
282+ {
283+ exec ( `${ process . execPath } -pe "const assert = require('assert');` +
284+ 'const interval = require(\'timers/promises\')' +
285+ '.setInterval(1000, null, { ref: false });' +
286+ 'interval[Symbol.asyncIterator]().next()' +
287+ '.then(assert.fail)"' ) . then ( common . mustCall ( ( { stderr } ) => {
288+ assert . strictEqual ( stderr , '' ) ;
289+ } ) ) ;
290+ }
291+
292+ {
293+ async function runInterval ( fn , intervalTime , signal ) {
294+ const input = 'foobar' ;
295+ const interval = setInterval ( intervalTime , input , { signal } ) ;
296+ let iteration = 0 ;
297+ for await ( const value of interval ) {
298+ const time = Date . now ( ) ;
299+ assert . strictEqual ( value , input ) ;
300+ await fn ( time , iteration ) ;
301+ iteration ++ ;
302+ }
303+ }
304+
305+ {
306+ // Check that we call the correct amount of times.
307+ const controller = new AbortController ( ) ;
308+ const { signal } = controller ;
309+
310+ let loopCount = 0 ;
311+ const delay = 20 ;
312+ const timeoutLoop = runInterval ( ( ) => {
313+ loopCount ++ ;
314+ if ( loopCount === 5 ) controller . abort ( ) ;
315+ if ( loopCount > 5 ) throw new Error ( 'ran too many times' ) ;
316+ } , delay , signal ) ;
317+
318+ assert . rejects ( timeoutLoop , / A b o r t E r r o r / ) . then ( common . mustCall ( ( ) => {
319+ assert . strictEqual ( loopCount , 5 ) ;
320+ } ) ) ;
321+ }
322+
323+ {
324+ // Check that if we abort when we delay long enough
325+ const controller = new AbortController ( ) ;
326+ const { signal } = controller ;
327+
328+ let prevTime ;
329+ const delay = 25 ;
330+ const timeoutLoop = runInterval ( ( time , iteration ) => {
331+ if ( iteration === 5 ) controller . abort ( ) ;
332+ // Give some slack because of timers
333+ if ( prevTime && ( time - prevTime < ( delay - 5 ) ) ) {
334+ const diff = time - prevTime ;
335+ throw new Error ( `${ diff } between iterations, lower than ${ delay } ` ) ;
336+ }
337+ prevTime = time ;
338+ } , delay , signal ) ;
339+
340+ assert . rejects ( timeoutLoop , / A b o r t E r r o r / ) . then ( common . mustCall ( ) ) ;
341+ }
342+
343+ {
344+ // Check that if we abort when we have some callbacks left,
345+ // we actually call them.
346+ const controller = new AbortController ( ) ;
347+ const { signal } = controller ;
348+ const delay = 10 ;
349+ let totalIterations = 0 ;
350+ const timeoutLoop = runInterval ( async ( time , iterationNumber ) => {
351+ if ( iterationNumber === 1 ) {
352+ await setTimeout ( delay * 3 ) ;
353+ controller . abort ( ) ;
354+ }
355+ if ( iterationNumber > totalIterations ) {
356+ totalIterations = iterationNumber ;
357+ }
358+ } , delay , signal ) ;
359+
360+ timeoutLoop . catch ( common . mustCall ( ( ) => {
361+ assert . ok ( totalIterations >= 3 ) ;
362+ } ) ) ;
363+ }
364+ }
0 commit comments