Skip to content

Commit 4ebe38b

Browse files
Linkgorondanielleadams
authored andcommitted
timers: introduce setInterval async iterator
Added setInterval async generator to timers\promises. Utilises async generators to provide an iterator compatible with `for await`. Co-Authored-By: Fabian Cook <hello@fabiancook.dev> fix message PR-URL: #37153 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent bfe0b46 commit 4ebe38b

3 files changed

Lines changed: 327 additions & 13 deletions

File tree

‎doc/api/timers.md‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,38 @@ added: v15.0.0
363363
*`signal` {AbortSignal} An optional `AbortSignal` that can be used to
364364
cancel the scheduled `Immediate`.
365365

366+
### `timersPromises.setInterval([delay[, value[, options]]])`
367+
<!-- YAML
368+
added: REPLACEME
369+
-->
370+
371+
Returns an async iterator that generates values in an interval of `delay` ms.
372+
373+
*`delay` {number} The number of milliseconds to wait between iterations.
374+
**Default**: `1`.
375+
*`value` {any} A value with which the iterator returns.
376+
*`options` {Object}
377+
*`ref` {boolean} Set to `false` to indicate that the scheduled `Timeout`
378+
between iterations should not require the Node.js event loop to
379+
remain active.
380+
**Default**: `true`.
381+
*`signal` {AbortSignal} An optional `AbortSignal` that can be used to
382+
cancel the scheduled `Timeout` between operations.
383+
384+
```js
385+
(asyncfunction() {
386+
const { setInterval } =require('timers/promises');
387+
constinterval=100;
388+
forawait (conststartTimeofsetInterval(interval, Date.now())) {
389+
constnow=Date.now();
390+
console.log(now);
391+
if ((now - startTime) >1000)
392+
break;
393+
}
394+
console.log(Date.now());
395+
})();
396+
```
397+
366398
[Event Loop]: https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/#setimmediate-vs-settimeout
367399
[`AbortController`]: globals.md#globals_class_abortcontroller
368400
[`TypeError`]: errors.md#errors_class_typeerror

‎lib/timers/promises.js‎

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ const {
1818
codes: {ERR_INVALID_ARG_TYPE}
1919
}=require('internal/errors');
2020

21-
const{ validateAbortSignal }=require('internal/validators');
21+
const{
22+
validateAbortSignal,
23+
validateBoolean,
24+
validateObject,
25+
}=require('internal/validators');
2226

2327
functioncancelListenerHandler(clear,reject){
2428
if(!this._destroyed){
@@ -111,7 +115,59 @@ function setImmediate(value, options = {}) {
111115
()=>signal.removeEventListener('abort',oncancel)) : ret;
112116
}
113117

118+
asyncfunction*setInterval(after,value,options={}){
119+
validateObject(options,'options');
120+
const{ signal, ref =true}=options;
121+
validateAbortSignal(signal,'options.signal');
122+
validateBoolean(ref,'options.ref');
123+
124+
if(signal?.aborted)
125+
thrownewAbortError();
126+
127+
letonCancel;
128+
letinterval;
129+
try{
130+
letnotYielded=0;
131+
letcallback;
132+
interval=newTimeout(()=>{
133+
notYielded++;
134+
if(callback){
135+
callback();
136+
callback=undefined;
137+
}
138+
},after,undefined,true,true);
139+
if(!ref)interval.unref();
140+
insert(interval,interval._idleTimeout);
141+
if(signal){
142+
onCancel=()=>{
143+
// eslint-disable-next-line no-undef
144+
clearInterval(interval);
145+
if(callback){
146+
callback(PromiseReject(newAbortError()));
147+
callback=undefined;
148+
}
149+
};
150+
signal.addEventListener('abort',onCancel,{once: true});
151+
}
152+
153+
while(!signal?.aborted){
154+
if(notYielded===0){
155+
awaitnewPromise((resolve)=>callback=resolve);
156+
}
157+
for(;notYielded>0;notYielded--){
158+
yieldvalue;
159+
}
160+
}
161+
thrownewAbortError();
162+
}finally{
163+
// eslint-disable-next-line no-undef
164+
clearInterval(interval);
165+
signal?.removeEventListener('abort',onCancel);
166+
}
167+
}
168+
114169
module.exports={
115170
setTimeout,
116171
setImmediate,
172+
setInterval,
117173
};

0 commit comments

Comments
 (0)