Venelin
Venelin

Reputation: 3308

JavaScript - How to hold for loop until you receive a function callback

Here is my for loop:

    for (var d = startDate; d <= in30DaysDate; d.setDate(d.getDate() + 1)) {
        var loopDay = new Date(d);
        DoYourDaylyJob();
        console.log("Day:" + loopDay);
    }

What should i put in function DoYourDailyJob() to prevent the loop to go on the next day before it do it's "daily" job?

I hope i have described it well enough. Should i attach any kind of function callback at DoYourDailyJob, but if so how that is going to prevent the loop from proceeding until it receives response from the function ?

I'm not aware if this is possible. If it's possible can you show an example as an answer to this question ?

Upvotes: 1

Views: 1075

Answers (5)

raul.vila
raul.vila

Reputation: 1984

Using a callback function, you replace the for with a recursive loop:

executeIteration(startDate);

function executeIteration(d) {
    if (d <= in30DaysDate)
        return;

    var loopDay = new Date(d);

    DoYourDaylyJob(function(valueFromDoYourDaylyJob) {
        executeIteration(d.setDate(d.getDate() + 1)));
    });
}

function DoYourDaylyJob(callback) {
    // Do your dayly job
    var valueToReturn = "foo";
    callback(valueToReturn);
}

Upvotes: 4

samanime
samanime

Reputation: 26527

Short answer, you can't (at least without a super ugly blocking call that I can't recommend strongly enough that you avoid).

Instead, make it asynchronous.

If DoYourDailyJob() is something that is asynchronous, that you'll either want to make it:

  • accept a callback function which is called when complete
  • return a Promise that is resolved when complete

The Promise method tends to be more preferable these days:

function DoYourDailyJob() {
  return new Promise((resolve, reject) => {
    // do stuff
    // call resolve() when done
    // call reject() if there is an error
  });
}

In your for loop, create an array of Dates you want to process:

const dates = [];
for (var d = startDate; d <= in30DaysDate; d.setDate(d.getDate() + 1)) {
  dates.push(new Date(d));
}

With your list of Dates, you can then either run them all in parallel:

Promise.all(dates.map(d => DoYourDailyJob(d))
  .then(() => console.log('all done'));

Or, if they need to be run one in a time (which may be the case since you don't pass in the date), you can essentially have a "queue" and a queue running function which will keep going until all of them are done:

const runNextDay = () => {
  if (!dates.length) {
    return Promise.resolve(); // all done
  }

  const day = dates.shift();
  return DoYourDailyJob().then(() => console.log('loop date', day))
    .then(runNextDay); // call the next day when its done
};

runNextDay()
  .then(() => console.log('all done'));

Upvotes: 0

somethinghere
somethinghere

Reputation: 17330

Just refactor it so its recursive:

var day = 0;
var loops = 10;

function DoYourDailyJob(){

    var loopDay = new Date(d);
    console.log("Day:" + loopDay);

    if( day++ < loops ){

        DoYourDailyJob();

    }

}

DoYourDailyJob();

Upvotes: 1

TKoL
TKoL

Reputation: 13892

All those comments are wrong, it is absolutely possible, in some environments.

If you have async await available, you can do it quite easily. Just make DoYourDailyJob(); an async function (returns a promise) and do

for () {
   await DoYourDailyJob();
}

If you don't have async await available, comment that here and we can do something similar with raw promises.

Upvotes: -1

Jonas Wilms
Jonas Wilms

Reputation: 138235

Just return a Promise from DoYourDailyJob, then its as simple as:

 (async function() {

 for (var d = startDate; d <= in30DaysDate; d.setDate(d.getDate() + 1)) {
    var loopDay = new Date(d);
    await DoYourDaylyJob();
    console.log("Day:" + loopDay);
 }

 })()

Upvotes: 9

Related Questions