What is the purpose of the Promises Timers API on Node.js?

Asked

Viewed 73 times

4

Recently, in the version V16.0.0 of Node.js, added the Promises Timers API, and from what I understand, it’s about alter the behavior of standard timers (setTimeout, setImmediate, etc...). These timers return objects NodeJS.Timeout, in this way:

If made a console.log(setTimeout(() => {}, 0)), we have:

Timeout {
  _idleTimeout: 1000,
  _idlePrev: [TimersList],
  _idleNext: [TimersList],
  _idleStart: 34,
  _onTimeout: [Function (anonymous)],
  _timerArgs: undefined,
  _repeat: null,
  _destroyed: false,
  [Symbol(refed)]: true,
  [Symbol(kHasPrimitive)]: false,
  [Symbol(asyncId)]: 7,
  [Symbol(triggerId)]: 0
}

Now, thanks to this API, the new functions return an object Promise.

In this example (adapted by me) from the documentation, we have:

import { setTimeout } from 'timers/promises';

const twoSeconds = 2_000;

const res = await setTimeout(twoSeconds, 'result');

// Exibe a string "result" depois de 2 segundos.
console.log(res);

This function above is much simpler and takes less code to build and understand. Note that this function returns a promise, which allows the use of the await. This new API "kind of" makes a "promissification" of the timer setTimeout behind the scenes.

In the example above, if I make a console.log(setTimeout(() => {}, 0)), I’ll have at the terminal:

Promise { <pending> }

I wanted to know:

  • If that "promissification" of timers is the main purpose of this new implementation.
  • She solves what problems?

This API was inserted in version v15.0.0 as experimental and was stabilized in version V16.0.0 of Node.js.

  • 3

    As most of the other Node Apis are promise-based, I believe they have created this new version of the timers to make it easier to use with these other Apis. Remembering that the "standard" Node timers API was no longer standard - but a transposition of the implementation that exists in browsers, part of the DOM API (I think).

  • @bfavaretto Yes! would be the API of window in the case? setTimeout() is similar to API window.setTimeout of browsers.

  • Yeah, that’s the one I’m talking about.

1 answer

3


It has no purpose very different from those that already exist; the idea is to facilitate the use of timers in cases where promises are used. I’m sure these new Apis have been coming in strong on Node.js, like Node.js itself fs/promises.

Will not change the behavior of functions setTimeout, setInterval and setImmediate that already exist, because that would be a Breaking change very large. What will occur is the establishment of three new functions, of the same name, qualified in the module native timers/promises.

Of documentation:

The API timers/promises provides an alternative set of timer functions returning objects Promise.

It is very common to find functions like:

function wait(interval = 0) {
  return new Promise((resolve) => setTimeout(resolve, interval));
}

To create a function that returns a promise that is automatically resolved after a certain time interval. There are several packages in npm with a substantial number of downloads who also do this kind of thing.

The new promise-based Node.js API makes this kind of functionality "native". The interesting thing is that it provides means for cancellation and creation of intervals using asynchronous iterators, which were not possible with simple functions such as wait, demonstrated above.

Some examples:

  1. Creation of a timeout

    As an alternative to wait proposed above, it is now possible to use native Apis from Node.js:

    import { setTimeout } from 'timers/promises';
    
    console.log('Foo');
    await setTimeout(1000); // Espera 1s
    console.log('Bar'); // Imprime `Bar` após 1s.
    

    Note that since the new API is based on promises, the await can be used in asynchronous functions or top-level module to "wait" for the timeout.

  2. Creation of a range

    The ranges created by the API timers/promises makes use of asynchronous iterators, returning a promise at each time interval. It gets extremely interesting with loops for await .. of:

    import { setInterval } from 'timers/promises';
    
    for await (const _ of setInterval(100)) {
      console.log(new Date().toLocaleString('pt-BR')); // Irá imprimir a cada 0.1s
    }
    
  3. To documentation expands a little further on the examples and arguments of each of the three functions, setImmediate, setTimeout and setInterval.


It’s interesting to mention that, like setTimeout and setInterval return promises (not an identifier), it is necessary to use Apis as AbortController to cancel the timer.

An example using setInterval:

import { setInterval, setTimeout } from 'timers/promises';

const controller = new AbortController();

setTimeout(500).then(() => {
  controller.abort();
});

let i = 0;

try {
  // O segundo argumento (passei `null`) é o valor
  // de resolução de cada promessa.
  for await (const _ of setInterval(100, null, { signal: controller.signal })) {
    console.log('Atual:', ++i);
  }
} catch (err) {
  if (err.code === 'ABORT_ERR') {
    console.log('Abortado!');
  }
}

In the case of setInterval, when used with bows for await .. of, it is also possible to use the break to exit the loop and therefore end the interval. For example:

import { setInterval } from 'timers/promises';

let i = 0;
for await (const _ of setInterval(100)) {
  console.log('Atual:', ++i);

  if (i === 5) {
    break;
  }
}
  • I was curious about this AbortController, I’ll take a look at it calmly. A question, it was you who asked how to cancel an asynchronous call with Next (I think) or something like that?

  • It was Wallace, @Cmtecardeal! But it was me who answered!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.