@@ -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,158 @@ 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 ( ( ) => {
177+ assert . doesNotReject ( setTimeout ( 10 , undefined , { signal } ) . then ( common . mustCall ( ( ) => {
86178 ac . abort ( ) ;
87- } ) ;
179+ } ) ) ) . then ( common . mustCall ( ) ) ;
88180}
89181{
90182 // Check that aborting after resolve will not reject.
91183 const ac = new AbortController ( ) ;
92184 const signal = ac . signal ;
93- setImmediate ( 10 , { signal } ) . then ( ( ) => {
185+ assert . doesNotReject ( setImmediate ( 10 , { signal } ) . then ( common . mustCall ( ( ) => {
94186 ac . abort ( ) ;
187+ } ) ) ) . then ( common . mustCall ( ) ) ;
188+ }
189+
190+ {
191+ [ 1 , '' , Infinity , null , { } ] . forEach ( ( ref ) => {
192+ const iterable = setInterval ( 10 , undefined , { ref } ) ;
193+ assert . rejects ( ( ) => iterable [ Symbol . asyncIterator ] ( ) . next ( ) , / E R R _ I N V A L I D _ A R G _ T Y P E / )
194+ . then ( common . mustCall ( ) ) ;
195+ } ) ;
196+
197+ [ 1 , '' , Infinity , null , { } ] . forEach ( ( signal ) => {
198+ const iterable = setInterval ( 10 , undefined , { signal } ) ;
199+ assert . rejects ( ( ) => iterable [ Symbol . asyncIterator ] ( ) . next ( ) , / E R R _ I N V A L I D _ A R G _ T Y P E / )
200+ . then ( common . mustCall ( ) ) ;
201+ } ) ;
202+
203+ [ 1 , '' , Infinity , null , true , false ] . forEach ( ( options ) => {
204+ const iterable = setInterval ( 10 , undefined , options ) ;
205+ assert . rejects ( ( ) => iterable [ Symbol . asyncIterator ] ( ) . next ( ) , / E R R _ I N V A L I D _ A R G _ T Y P E / )
206+ . then ( common . mustCall ( ) ) ;
95207 } ) ;
96208}
97209
@@ -165,3 +277,87 @@ process.on('multipleResolves', common.mustNotCall());
165277 assert . strictEqual ( stderr , '' ) ;
166278 } ) ) ;
167279}
280+
281+ {
282+ exec ( `${ process . execPath } -pe "const assert = require('assert');` +
283+ 'const interval = require(\'timers/promises\')' +
284+ '.setInterval(1000, null, { ref: false });' +
285+ 'interval[Symbol.asyncIterator]().next()' +
286+ '.then(assert.fail)"' ) . then ( common . mustCall ( ( { stderr } ) => {
287+ assert . strictEqual ( stderr , '' ) ;
288+ } ) ) ;
289+ }
290+
291+ {
292+ async function runInterval ( fn , intervalTime , signal ) {
293+ const input = 'foobar' ;
294+ const interval = setInterval ( intervalTime , input , { signal } ) ;
295+ let iteration = 0 ;
296+ for await ( const value of interval ) {
297+ const time = Date . now ( ) ;
298+ assert . strictEqual ( value , input ) ;
299+ await fn ( time , iteration ) ;
300+ iteration ++ ;
301+ }
302+ }
303+
304+ {
305+ // check that we call the correct amount of times.
306+ const controller = new AbortController ( ) ;
307+ const { signal } = controller ;
308+
309+ let loopCount = 0 ;
310+ const delay = 20 ;
311+ const timeoutLoop = runInterval ( ( ) => {
312+ loopCount ++ ;
313+ if ( loopCount === 5 ) controller . abort ( ) ;
314+ if ( loopCount > 5 ) throw new Error ( 'ran too many times' ) ;
315+ } , delay , signal ) ;
316+
317+ assert . rejects ( timeoutLoop , / A b o r t E r r o r / ) . then ( common . mustCall ( ( ) => {
318+ assert . strictEqual ( loopCount , 5 ) ;
319+ } ) ) ;
320+ }
321+
322+ {
323+ // Check that if we abort when we delay long enough
324+ const controller = new AbortController ( ) ;
325+ const { signal } = controller ;
326+
327+ let prevTime ;
328+ const delay = 25 ;
329+ const timeoutLoop = runInterval ( ( time , iteration ) => {
330+ if ( iteration === 5 ) controller . abort ( ) ;
331+ // give some slack because of timers
332+ if ( prevTime && ( time - prevTime < ( delay - 5 ) ) ) {
333+ const diff = time - prevTime ;
334+ throw new Error ( `${ diff } between iterations, lower than ${ delay } ` ) ;
335+ }
336+ prevTime = time ;
337+ } , delay , signal ) ;
338+
339+ assert . rejects ( timeoutLoop , / A b o r t E r r o r / ) . then ( common . mustCall ( ) ) ;
340+ }
341+
342+ {
343+ // Check that if we abort when we have some callbacks left,
344+ // we actually call them.
345+ const controller = new AbortController ( ) ;
346+ const { signal } = controller ;
347+ const delay = 10 ;
348+ let totalIterations = 0 ;
349+ const timeoutLoop = runInterval ( async ( time , iterationNumber ) => {
350+ if ( iterationNumber === 1 ) {
351+ await setTimeout ( delay * 3 ) ;
352+ controller . abort ( ) ;
353+ }
354+ if ( iterationNumber > totalIterations ) {
355+ totalIterations = iterationNumber ;
356+ }
357+ } , delay , signal ) ;
358+
359+ timeoutLoop . catch ( common . mustCall ( ( ) => {
360+ assert . ok ( totalIterations >= 3 ) ;
361+ } ) ) ;
362+ }
363+ }
0 commit comments