user3871
user3871

Reputation: 12718

sequentially call multiple setTimeouts with returning promises

I am trying to syncronously run an array of async functions using eachSeries from async library.

According to this SO Post, they say

The difference with async.eachSeries is that each iteration will wait for the async operation to complete before starting the next one.

This is what I want.

Question: I'm not quite understanding how to use eachSeries to call the next async setTimeout only after the returning internal promise next() resolves.

I push two async setTimeout functions into my queue:

this.dialogTimerQueue.push(this.getNextDialogTimer(data, 1000));
this.dialogTimerQueue.push(this.getNextDialogTimer(data2, 1000));
console.log(this.dialogTimerQueue); //  [101, 102]

Then attempt to iterate through:

// https://caolan.github.io/async/docs.html#eachSeries
async.eachSeries(this.dialogTimerQueue, (result) => {

});

The problem is, both setTimeouts run in parallel. They need to run one after another.

getNextDialogTimer returns a new setTimeout which itself returns a Promise next()

getNextDialogTimer: function(dialog, ms) {
    let foo = setTimeout(() => {
        // only when next() completes, call next in async series
        return this.next(dialog);
    }, this.npcDialogDelay * ms);

    console.log('Timeout: ', foo); // 101 or 102
    return foo;
},

next() promise:

// Return promise
next: function(dialog) {
    var promiseTest = this.screenObj.conversation().addDialogToCenterScreen('npc', dialog, '');
    console.log('Next: ', promiseTest);
    return promiseTest;
},

Console.log shows as:

enter image description here


    async.eachSeries(this.dialogTimerQueue, ({dialog, ms}, cb) => {
        setTimeout(() => {
            console.log('RESOLVING ' + dialog);
            this.next(dialog).then(() => {
                cb();
            });
        }, this.npcDialogDelay * ms);
    });

Upvotes: 2

Views: 110

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 370819

The problem is that when you call getNextDialogTimer, you start / set the timeout immediately - that's the first line of the function. They start as soon as they're added to the queue, which is not what you want.

You could queue a callable function instead, which will start the timeout when called. Or, you could just queue the dialog, ms items, which will probably be easier to understand, eg:

const dialogTimerQueue = [];
const data = 'foo';
const data2 = 'bar';
const npcDialogDelay = 1;
const next = () => new Promise(resolve =>
  setTimeout(() => {
    console.log('next resolved');
    resolve();
  }, 500)
);

dialogTimerQueue.push({ dialog: data, ms: 1000 });
dialogTimerQueue.push({ dialog: data2, ms: 1000 });
async.eachSeries(dialogTimerQueue, ({ dialog, ms }, cb) => {
  setTimeout(() => {
    console.log('resolving ' + dialog);
    next().then(cb);
  }, npcDialogDelay * ms);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/async/2.6.1/async.min.js"></script>

Upvotes: 1

Related Questions