Jeff Jeff - 6 months ago 11
Javascript Question

Using generators to pause until promise resolves

I have a batch job in node.js that: copies files into a directory, does analysis on files, then removes files.

I would like to iterate over an array of jobs and use generators to pause execution until that batch job is complete before starting another job. Here is what I have so far:



const cars = ["toyota", "honda", "acura"];

function copyFilesAndRunAnalysis(car) {
return new Promise(function(resolve, reject) {
setTimeout(function() { // simulate some delay
resolve(); // control should return to generator here
}, 1000);
});
}

function* doCar(car) {
yield copyFilesAndRunAnalysis(car);
}

// BEGIN HERE
console.log('start here');
carBatch = doCar(cars[0]);
carBatch.next(); // confusion here!!!
carBatch.next(); // should this all be in a forEach loop?





What I'd like to do is have a forEach that loops over each car, does all the respective work in the
copyFilesAndRunAnalysis
method -- pausing until
Promise.resolve()
and then on to the next one. Trying forEach does not make anything run at all.

Answer

You do not use .value at js at Question. The .value of the next() object yielded by Generator would be the Promise returned from copyFilesAndRunAnalysis, where .then() could be chained to .next().value(), Array.prototype.shift() could be used to recursively call doCar until no items remain within original or copy of cars array.

const cars = ["toyota", "honda", "acura"];
let carsCopy = cars.slice(0);

function copyFilesAndRunAnalysis(car) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() { // simulate some delay
      resolve(car); // control should return to generator here
    }, 1000);
  })
}

function* doCar(cars) {
  yield copyFilesAndRunAnalysis(cars);
}

// BEGIN HERE
console.log("start here");
carBatch = doCar(carsCopy.shift());
carBatch.next().value.then(function re(data) {
  console.log(data);
  return carsCopy.length 
         ? doCar(carsCopy.shift()).next().value.then(re) 
         : "complete"
})
.then(function(complete) {
  console.log(complete); 
})

Note, the same process can be achieved utilizing Promise, recursion; without using a Generator function.

const cars = ["toyota", "honda", "acura"];
let carsCopy = cars.slice(0);

function copyFilesAndRunAnalysis(car) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() { // simulate some delay
      resolve(car); // control should return to generator here
    }, 1000);
  })
}

// BEGIN HERE
console.log("start here");
carBatch = copyFilesAndRunAnalysis(carsCopy.shift());
carBatch.then(function re(data) {
  console.log(data);
  return carsCopy.length 
         ? copyFilesAndRunAnalysis(carsCopy.shift()).then(re) 
         : "complete"
})
// do stuff when all items within `cars` have been 
// processed through `copyFilesAndRunAnalysis`
.then(function(complete) {
  console.log(complete); 
})