How to improve code workflow without using synchronous ajax?

1

How can I improve this script?

The function copiaArea() should get the first return from the array and send it to the windows clipboard, detail: I'm developing for IE, it works exclusively in this function. However, the global var numero does not receive the time in the 2nd call of the listaNumeros() , after adicionarNúmero() (generated by trigger in the BD, for reasons of date processing and direct numbering sequence in mysql.)

The question is, are the contraindications of using async:false in ajax relevant here?

Another detail is that this only runs on a local network server, it does not depend on the internet.

/*
* Loader da numeração
* @author marcelo aymone
*/

$(document).ajaxStart(function() {
    $('#loading').show();
});

$(document).ajaxStop(function() {
    $('#loading').hide();
});

var ip;
var numero;

function inserirLinha(array) {
    var linha = $("<tr>");
    var col = "";
    col += "<td>" + array.num + "</td>";
    col += "<td>" + array.time + "</td>";
    linha.append(col);
    if (array.ip == ip) {
        linha.toggleClass("info");
    }
    $("#numeros").append(linha);
}

function sysMsg(msg) {
    $("#alertas").empty().append(msg);
}

function copiaArea(txt) {
    if (window.clipboardData && clipboardData.setData) {
        clipboardData.setData('text', txt);
    }
}

function atualizaTabela(data) {
    var msg = "";
    if (data.status) {
        msg = "<div class=\"alert alert-success text-center\">";
        msg += "<h4>Sucesso!</h4>";
        msg += "Seu número foi gerado com sucesso!";
        msg += "</div>";
    } else {
        msg = "<div class=\"alert alert-error\">";
        msg += "<h4>Sucesso!</h4>";
        msg += "Ocorreu um erro e não foi possível gerar um número.";
        msg += "</div>";
    }
    $("#numeros").empty();
    listarNumeros();
    sysMsg(msg);
}

/*
* ListarNumeros recebe o seguinte json:
* {"lista":[{"num":"2014\/1618","ip":"10.120.2.35","time":"15\/05\/2014"}],"cliente":"10.120.2.35"}
**Possui \/ por causa do json_encode(), mas funciona ok.
*/

function listarNumeros() {
    $.ajaxSetup({cache: false, async:false});
    $.getJSON("/intracake/Numeros/listar.json")
            .done(function(data) {
                ip = data.cliente;
                numero = data.lista[0].num; //Pega o 1 resultado do array, último num gerado.
                $.each(data.lista, function(index, array) {
                    inserirLinha(array);
                });
            });
}
/*
* Recebe como retorno do json: {"status":true}
*/
function adicionarNumero() {
    $.post("/intracake/Numeros/adicionar.json")
            .done(function(data) {
                atualizaTabela(data);
                copiaArea(numero);
            });
}

$(document).ready(function() {
    listarNumeros();
});

Html script + php (cakephp):

<?php
 echo $this->Html->script('numeros-run', array('inline' => false));
?>
<style>
    .centralizado {
        margin: 0 auto !important;
        float: none !important;
    }
    .table td, .table th {
        text-align: center;   
    }
</style>

<div class="span10">
    <div id="alertas"></div>
    <p class="text-center"><button class="btn btn-large btn-primary" type="button" onclick="adicionarNumero();">Gerar número!</button></p>
    <div id="loading" class="text-center"><p><img src="img/ajax-loader.gif"></p></div>
    <p class="text-center lead">Últimos números gerados:</p>
    <div class="span4 centralizado">
        <table id="numeros" class="table table-bordered">
        </table>
    </div>
    <p class="text-center">
        <i class="icon-info-sign"></i>
        Todos números gerados pelo seu ip, 
        aparecem destacados em azul.
    </p>
    <p class="text-center">
        <i class="icon-info-sign"></i>
        Ao gerar um número, ele é enviado para a área de transferência do windows.<br>
        <i class="icon-info-sign"></i>
        Compatível apenas com Microsoft Internet Explorer.<br>
        <strong class="text-error">Você precisa aceitar na janela que abrirá</strong>, para que o número possa ser copiado automaticamente.<br>
        Depois basta você colar("ctrl+v") em qualquer lugar.
    </p>
</div>
    
asked by anonymous 15.05.2014 / 16:53

2 answers

5

If I understand correctly, the flow of the posted code, with the use of asynchronous ajax, is as follows:

  • Button clicked, adicionarNumero is called.
  • JSON ( adicionar.json ) received, atualizaTabela is called.
  • atualizaTabela calls listarNumeros .
  • copiaArea is called, passing the previous value of numero since the response of listar.json has not yet arrived.
  • The response from listar.json arrives and global numero is updated (too late!)
  • Solution

    Since you do not want to call copiaArea whenever listarNumeros is executed, but only after adicionarNumero , I suggest taking advantage of promises returned by jQuery's ajax methods, like this:

    function atualizaTabela(data) {
        var msg = "";
        if (data.status) {
            msg = "<div class=\"alert alert-success text-center\">";
            msg += "<h4>Sucesso!</h4>";
            msg += "Seu número foi gerado com sucesso!";
            msg += "</div>";
        } else {
            msg = "<div class=\"alert alert-error\">";
            msg += "<h4>Sucesso!</h4>";
            msg += "Ocorreu um erro e não foi possível gerar um número.";
            msg += "</div>";
        }
        $("#numeros").empty();
        return listarNumeros();
        sysMsg(msg);
    }
    
    function listarNumeros() {
        $.ajaxSetup({cache: false, async:false});
        return $.getJSON("/intracake/Numeros/listar.json").done(function(data) {
            ip = data.cliente;
            numero = data.lista[0].num; //Pega o 1 resultado do array, último num gerado.
            $.each(data.lista, function(index, array) {
                inserirLinha(array);
            });
        });
    }
    
    function adicionarNumero() {
        $.post("/intracake/Numeros/adicionar.json").done(function(data) {
            atualizaTabela(data).done(function(){
                copiaArea(numero);
            });
        });
    }
    
      

    Note: The solution below was proposed when one of the requirements was not clear to me

    It seems to me that to solve the problem it would be enough to remove the copiaArea call from the adicionarNumero function, and move on listarNumeros . With this you can even get rid of the global variable (on this, see Why using global variables is not a good practice? ). That is:

    function listarNumeros() {
        $.ajaxSetup({cache: false, async:false});
        $.getJSON("/intracake/Numeros/listar.json")
                .done(function(data) {
                    ip = data.cliente;
                    // remover a linha abaixo
                    //numero = data.lista[0].num; //Pega o 1 resultado do array, último num gerado.
    
                    // inserir a seguinte linha:
                    copiaArea(data.lista[0].num);
    
                    $.each(data.lista, function(index, array) {
                        inserirLinha(array);
                    });
                });
    }
    
    function adicionarNumero() {
        $.post("/intracake/Numeros/adicionar.json")
                .done(function(data) {
                    atualizaTabela(data);
                    // remover a linha abaixo
                    //copiaArea(numero);
                });
    }
    
        
    15.05.2014 / 19:20
    3

    You can use a global counter and a guard condition to synchronize the execution of your asynchronous actions. More or less as it is done in a Machine States .

    In your code, this would look like this (just the modifications):

    Excerpt 1:

    var estado = 0;
    
    function executaFim() {
        if (estado >= 3)
            copiaArea(numero);
    }
    

    Excerpt 2:

    function listarNumeros() {
        $.ajaxSetup({cache: false, async:false});
        $.getJSON("/intracake/Numeros/listar.json")
                .done(function(data) {
                    // seu código original
                    estado++;
                    executaFim();
                });
    }
    

    Section 3:

    function adicionarNumero() {
        $.post("/intracake/Numeros/adicionar.json")
                .done(function(data) {
                    // seu código original
                    estado++;
                    executaFim();
                });
    }
    
        
    15.05.2014 / 19:55