akaphenom
akaphenom

Reputation: 6888

How to iterate over the results of a generator function

Is there a better way to iterate over the results of a generator, my for loop is ugly:

for(let job = readyJob.next(); !job.done; job = readyJob.next()){ } 

In context there is a generator function that can determine if there is a batch of work, consisting of 1..* jobs (the generator may also return no jobs in the batch). There is a continuous loop that instantiates the generator and iterates over the batch doing work on the job (logging).

Is there a more elegant solution to this iteration problem. I mean this looks like a traditional iterator from Java/C# which isn't bad. Something like an "each" would be super readable... That's my hope anyhow.

 let getReadyJob = function *(instance){
    let numJobs = 7 ; // getRandomInt(0, 10) ;
    for(let i = 0; i < numJobs; i++) {
        yield {
            jobId: '' + instance + '::' + i,
            jobReadyOn: (new Date()).valueOf()
        };
    }
}

then

while(true){
    let readyJob = getReadyJob()

    for(let job = readyJob.next(); !job.done; job = readyJob.next()){
        console.log(JSON.stringify(job.value)) ;
    }
}

Upvotes: 12

Views: 8402

Answers (2)

Tiberiu C.
Tiberiu C.

Reputation: 3513

for ... of is the elegant solution but not overall supported, however while (!(next = cursor.next()).done) { is a very cryptic, and one might ask himself, how come (var x = someFunctionCall()) is evaluated to true and another would answer welcome to javascript.

For that reason and to and give the answer another shape, it can also be done using a recursive function.

function loopThose(items) {
    const item = items.next();

    // doStuff(item);

    if (!item.done) {
        loopThose(items);
    }
}

A true benefit is when async, try catch and custom continue condition come into play:

async function printKeys(items) {
    try {
       const item = await items.next();
       // doStuff(item);
       if (isConditionFulfil(item)) {
          await this.printKeys(items);
       }
    } catch (e){

    }
}

Where a generator function yields promises that might fail:

function * list(){
  for (var i = 0; i<10; i++){
     yield fetch(buildResourceUrl(i)).then(res => res.json())
  }
}

Upvotes: 2

Felix Kling
Felix Kling

Reputation: 816334

Yes, if your environment already supports for...of:

for (var job of readyJob) {
  // ...
}

If not, have seen this a couple of times:

var next;
while (!(next = readyJob.next()).done) {
   var job = next.value;
   // ...
}

Upvotes: 25

Related Questions