1

So, my function looks like so

async function* doIt(arr){
    let counter = 0;
    while(true) yield arr[counter++];
}

(async() => {
    let arr = [1,2,3];
    let x = doIt(arr);
    setTimeout(() => {arr.push(4)}, 3000);
    await x.next();
    await x.next();
    await x.next();
    await x.next(); //I want to pause here until 4 has arrived, instead, got undefined
})()

I was hoping await here would cause doIt to pause after 3 until 4 has arrived. how can I achieve this? is this doable? I need the program not halted while waiting for 4

Thanks

Das Raf
  • 55
  • 6
  • yes, I'm perfectly fine with not awaiting setTimeout, but I need `doIt` to pause until `4` arrive. – Das Raf Feb 01 '23 at 02:07
  • so, basically, I need `doIt` to await on `arr` I guess – Das Raf Feb 01 '23 at 02:08
  • 1
    This sounds like a bad idea. `doIt` would basically need to poll the array to get another element. Instead, [use a queue](https://stackoverflow.com/a/47157577/1048572) and put the `4` in it after 3s, which can immediately notify the consumer. – Bergi Feb 01 '23 at 02:24

2 Answers2

1

If you want the waiting action to be abstracted inside the generator, I think you'll need to connect the asynchronous arr.push(4) with the generator. As is, it's completely disconnected from it, so there's no good way inside doIt to determine when exactly the array will get populated (short of something gross like putting a setter on the array property and returning a Promise that resolves when the setter gets invoked). You will need to somehow restructure the code so that the arr.push callback can communicate to the generator that something has changed - the existing structure isn't suitable for it in the same way that an asynchronous action inside a dangling Promise can't be hooked into from the outside.

There are a few approaches that could be used, but one would be to pass promises to doIt as well. When a Promise resolves, that indicates that something in the array may have changed, and the generator can re-check the index.

async function* doIt(arr, ...promises){
    let counter = 0;
    while(true) {
      if (!arr.hasOwnProperty(counter)) {
        await Promise.any(promises);
      }
      if (arr.hasOwnProperty(counter)) {
        yield arr[counter++];
      }
    }
}

(async() => {
    console.log('start');
    let arr = [1,2,3];
    let x = doIt(
      arr,
      new Promise((res) => {
        setTimeout(
          () => {arr.push(4); res()},
          3000
        )
      })
    );
    await x.next();
    await x.next();
    await x.next();
    console.log('got 3');
    await x.next(); //I want to pause here until 4 has arrived, instead, got undefined
    console.log('got 4');
})()
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
0

You could create a promise and await that:

const p = new Promise(resolve => {
  setTimeout(() => {
    arr.push(4);
    resolve();
  }, 3000);
});

await x.next();
await x.next();
await x.next();

await p; // wait for 4

// do other stuff

ray
  • 26,557
  • 5
  • 28
  • 27
  • amazing, this might just work, I'm still outside, let me try this when I get back to my pc. if this works, I'll accept this answer. – Das Raf Feb 01 '23 at 02:11