Wait for pending executions to finish to proceed, JavaScript

2

This is the most practical example I found .. is an example where the server sends 2 messages (or more) followed and at the same time, it does not check if there is something running, in case if it should have wait until the end to send the new request.

I thought of creating a finite loop that expects a variable to be false to proceed, the variable would be the one that says the last request job "is over" but I think it is gambiarra.

    // CONFIGURACOES DA DB //
var db = new Dexie('teste');

db.version(1).stores({
    sequences: '++id,of'
});
db.open().
catch ();
// CONFIGURACOES DA DB //

var executionOrder = []; // tem como deixar vazio sem ter undefined?

// isso foi o exemplo mais pratico que encontrei.. é um exemplo em que o servidor envia 4 mensagens (ou mais) seguidas e ao "mesmo tempo", ele nao checa se há algo sendo executado, no caso se houvesse ele deveria esperar até o fim para enviar a nova requisiçao

setInterval(function () {
    var newOrder = ['NOVO'].reverse();
    executionOrder = executionOrder.concat(newOrder);
    execute('INIT');
}, 4000);

setInterval(function () {
    var newOrder = ['APAGA'].reverse();
    executionOrder = executionOrder.concat(newOrder);
    execute('INIT');
}, 4000);

setInterval(function () {
    var newOrder = ['NOVO'].reverse();
    executionOrder = executionOrder.concat(newOrder);
    execute('INIT');
}, 4000);

function execute(req) {
    if (req == 'INIT') {
        callback();
    }  if (req == 'NOVO') {
        db.sequences.add({
            of: '0'
        });
        console.log('ADD 1');
        callback();
    }  if (req == 'APAGA') {
        db.sequences.where("of").equalsIgnoreCase('0').each(function (seq) {
            db.sequences.delete(seq.id);
        }).then(function () {
            console.log('DEL ALL');
            callback();
        });
    }
};

function callback() {
    if (executionOrder.length) {
        var next = executionOrder.pop();
        execute(next);
    }
}

If you take a setInterval you will notice that everything happens well .. But with 2 or more it does not wait ..

Example working: link

    
asked by anonymous 04.04.2015 / 16:17

1 answer

3

The general idea of using a variable such as "semaphore" is OK (but to use it in a loop would be really tricky, and would not work), and how your code is structured can be done this with a minimum of effort:

  • Create the variable, initially allowing any execution:

    var semaforo = true; // Aberto
    
  • When you are going to perform something as time-consuming and asynchronous, close the traffic light:

    if (req == 'APAGA') {
        semaforo = false; // Fechado
        db.sequences.where("of").equalsIgnoreCase('0').each(function (seq) {
            db.sequences.delete(seq.id);
        }).then(function () {
            console.log('DEL ALL');
            semaforo = true; // A execução demorada acabou, aberto de novo
            callback();
        });
    }
    

    Do not forget to do this for every asynchronous operation, closing the traffic light before it starts (not in the middle).

  • Finally, before executing anything, check that the semaphore is open:

    function callback() {
        if (semaforo && executionOrder.length) {
    

    If it is not, it does not execute. But, when will he perform? Simple: As you call the callback at the end of each run, it will check again for pending operations and do them.

  • In your case, that's enough. But to make things more robust, I suggest you modify the callback to run not only one, but all pending actions one at a time (do not worry about the competition , the semaphore ensures that each operation waits for the last one to be completed):

    function callback() {
        while (semaforo && executionOrder.length) {
            var next = executionOrder.pop();
            execute(next);
        }
    }
    

    P.S. I also encountered a problem in how you are implementing a queue, reversing a list and using it as a stack works fine - as long as you do not add more elements to it. For if you do, these elements will go to the beginning of the queue, not to the end, messing up the order. Instead, I suggest using the list as the same queue, not as stack, by calling portanto shift em vez de pop ':

    var newOrder = ['NOVO']; // Sem o .reverse()
    executionOrder = executionOrder.concat(newOrder);
    
    ...
    
    var next = executionOrder.shift(); // Em vez de .pop()
    

    Full example .

        
    04.04.2015 / 16:59