DEV Community

Discussion on: JavaScript Iterators and Generators: Asynchronous Iterators

Collapse
 
lorenzofox3 profile image
RENARD Laurent • Edited

I don't think we are talking about the same thing. I think it is totally fine to implement these interfaces yourself: usually when you implement a producer in a "low level" way you know what you are doing (cf Nodejs core maintainers).

I am talking about the code which consumes it, depending on the way you consume it, you might create leaks.

Consider the following producer (from my article I linked above):

const wait = delay => new Promise(resolve => {
    setTimeout(() => resolve(), delay);
});
const counterGen = async function * (limit = 10, delay = 100) {
 let iter = 1;
 try {
  while (true) {
   if (iter > limit) {
    break;
   }
   await wait(delay);
   yield iter;
   iter++;
  }
 } catch (e) {
  console.log('oops something is wrong');
  throw e;
 } finally {
  console.log('I have been released !!!');
 }
};

You could have written it by implementing the interfaces, it does not matter.

Just note it is doing some cleaning ("I have been released !!!"), it could be release file handle or whatever.

Now let's say you want to consume it and sum the 3 first values.

You can do it in a naive way

const sum = async iterator => {
    let i = 0;
    let sum = 0;
    while (i < 3) {
        const next = await iterator.next();
        if (next.done) {
            break;
        }
        sum += next.value;
        i++;
    }

    // VERY IMPORTANT IF YOU DO NOT WANT TO CREATE A LEAK
    // iterator.return();

    return sum;
};

sum(counterGen())
    .then(console.log);

And this code creates a leak if you don't pay attention and do not explicitly call return (you will not see the release message)

Whereas if you decide to go for "native construct" like for await statement you are safe

const sum = async iterator => {
    let i = 0;
    let sum = 0;
    for await (const v of iterator){
        if(i>=3){
            break;
        }
        sum+= v;
        i++
    }
    return sum;
};

sum(counterGen())
    .then(console.log);

I think tutorials and articles on iterators (and async iterators) do not stress enough that eventual issue.

This was my point :)

Thread Thread
 
jfet97 profile image
Andrea Simone Costa

Uh I've totally misunderstood your previous message!

Yes you are right, the for-of and the for-await-of should be always preferred 🙂