4

I am building an app that must poll remote devices (generator fn sendRequests()) every 2 seconds.

What's the right way to call the generator fn using setInterval, which isn't a generator and doesn't yield

function * sendRequests() {
  // multiple remote async requests are sent
}

var timer = setInterval(() => {
  // yield sendRequests()
}, 2000)
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Tremendus Apps
  • 1,497
  • 12
  • 20
  • 1
    Why is that a generator function? Shouldn't it be an `async function` at most? Have you forgotten to wrap it in `co.wrap` (or whatever async runner library you are using)? – Bergi Mar 29 '17 at 17:21
  • I'll update the question for clarity but the function is a generator. Its on the AdonisJS platform that uses generators in place of promises and callbacks for async operations and is not yet prepped for ES7 async fns. In this case, the async action is a remote MODBUS/TCP request. – Tremendus Apps Mar 29 '17 at 17:26

2 Answers2

2

The problem with yielding from the setInterval callback is that yield can only yield to the generator function* that immediately contains it. Therefore, you can't yield from a callback.

What you can do from a callback is resolve a Promise, which your generator function can yield:

async function* pollGen() {
  yield new Promise((resolve, reject) => {
    setInterval(() => resolve(...), 2000);
  });

The problem with that is a Promise can only be settled once. Therefore, calling resolve every 2000ms won't do anything beyond the first call.

What you can do instead is call setTimeout repeatedly, in a while loop:

async function* pollGen() {
  let i = 0;
  while (i < 10)
    yield new Promise((resolve, reject) => {
      setTimeout(() => resolve(i++), 200);
    });
}

(async function main() {
  // for-await-of syntax
  for await (const result of pollGen())
    console.log(result);
}());

The new for-await-of syntax has been available since Node v9.2, and can be used in Node v10 or later without any flags.

Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
  • This works but your while loop is basically blocking the execution as long as the promise is not resolved which kinda defeat the purpose of your `setTimeout`. – Luke Skywalker Oct 22 '20 at 15:40
0

Since AdonisJS uses co() under the hood, I used @Bergi suggestion of wrapping in co()

function * sendRequests() {
  // multiple remote async requests are sent
}

var timer = setInterval(() => {
  co(function * () {
    yield sendRequests()
  })
}, 2000)
Tremendus Apps
  • 1,497
  • 12
  • 20