Eseguire una richiesta AJAX dopo che un'altra richiesta AJAX è terminata

14 ott 2013, 12:08:59
Visualizzazioni: 177K
Voti: 6

Un file JS sta effettuando una chiamata ajax. All'interno del success di questa chiamata ajax viene effettuata un'altra chiamata AJAX. La seconda chiamata verifica se l'email è già stata registrata. Se è già registrata, la seconda chiamata AJAX non riceve dati di ritorno come mostrato in firebug e nella console Chrome. Tuttavia, lo stesso codice funziona correttamente in localhost mentre il problema menzionato si verifica SOLO sul server online.

La pagina ospitata si trova su http://twmobilefitness.com/signup/. Il problema si verifica quando si fa clic sul link 'Register Now' alla fine. È necessario registrarsi due volte con lo stesso indirizzo email per far verificare il problema.

JS:

$.ajax( {
    url : base_url+"/wp-admin/admin-ajax.php",
    type : 'GET',
    cache : false,
    data : 'action=check_user_name&'
           + Math.floor( ( Math.random() * 100 ) +1 )
           + '&user_name='+user_name,
    success : function( result ) {
        if ( parseInt( result ) == 0 ) {
            $( ".result" ).html( '<span class="error">Nome utente non disponibile </span>' );
        } else if ( parseInt( result ) == 1 ) {
            $.ajax( {
                url : base_url 
                    + "/wp-admin/admin-ajax.php",
                type : 'GET',
                cache : false,
                data : 'action=check_email_used&'
                    + Math.floor( ( Math.random() *100 ) +1 )
                    + '&email=' + email,
                success : function( result_email ) {
                    if ( parseInt( result_email ) == 0 ) {
                        $( ".result" ).html( '<span class="error">Email già utilizzata </span>' );
                    } else if ( parseInt( result_email ) == 1 ) {
                        $( ".result" ).html( '' );      
                        $( ".signup_div" ).hide();
                        $( ".signup_emergency_contact" ).show();
                    }
                }
            } );
        }
    }   
} );    

functions.php contiene

add_action('wp_ajax_check_user_name','check_user_name');
add_action('wp_ajax_nopriv_check_user_name','check_user_name');

add_action( 'wp_ajax_check_email_used','check_email_used' );
add_action( 'wp_ajax_nopriv_check_email_used','check_email_used' );
function check_user_name() {
    global $wpdb;

    $user_name = trim( $_GET['user_name'] );
    $MobTraining = new MobTraining();
    $table =trim( "{$wpdb->prefix}users" );
    $array_where['user_login'] = $user_name;
    $sql_fetch = $MobTraining->fetch( $table, $array_where );
    $row = $wpdb->get_results( $sql_fetch, ARRAY_A );
    if ( sizeof( $row ) != 0 ) {
        echo '0';
    } else {
        echo '1';
    }
    die();
}

function check_email_used() {
    global $wpdb;

    $email = trim( $_GET['email'] );
    $MobTraining = new MobTraining();
    $table = trim( "{$wpdb->prefix}users" );
    $array_where['user_email'] = $email;
    $sql_fetch = "SELECT * FROM $table WHERE `user_email`='$email'";
    $row = $wpdb->get_results( $sql_fetch, ARRAY_A );
    if ( sizeof( $row ) != 0 ) {
        echo '0';
    } else {
        echo '1';
    }
    die();
}

Come far funzionare il codice sul server online?

0
Tutte le risposte alla domanda 2
7
14

Quello che stai riscontrando (AJAX funziona localmente, ma non sul server) è un problema di ritardo. Localmente tutto funziona così velocemente che non riesci a vedere il problema. In breve, questo è il tuo problema:

Callback AJAX (A) viene eseguito > Callback AJAX (B) non sa che deve aspettare (A) > Non riesci a vedere il problema nella tua installazione locale perché (A) termina troppo velocemente.

Quindi devi trovare un modo per dire al tuo Callback (B) che deve aspettare (A). Ecco come:

Registrare script e spostare dati da PHP a JS

Registra e accoda i tuoi script e localizza i dati nel modo corretto: incapsula tutto in una funzione o metodo e aggancialo a wp_enqueue_scripts (pubblico/temi), login_enqueue_scripts (password/login/registrazione) o admin_enqueue_scripts. Poi usa wp_localize_script() per spostare i dati da PHP a JS e renderli accessibili lì.

add_action( 'admin_enqueue_scripts', 'wpse118772jsObject' );
function wpse118772jsObject()
{
    $scriptHandle = 'custom-script-name';
    // Dovrebbe essere diviso in funzioni o metodi separati
    wp_register_script(
        $scriptHandle,
        plugins_url( __FILE__, 'your/path' ),
        array( 'jquery' ),
        plugin_dir_path( __FILE__ ).'your/path' ),
        true
    );

    wp_enqueue_script( $scriptHandle );

    wp_localize_script(
        $scriptHandle,
        'pluginObject',
        array(
                'ajaxURl' => admin_url( 'admin_ajax.php' ),
                'custom'  => array(
                        // dati personalizzati qui
                ),
        ),
    );
}

Come usare jQuery AJAX nel modo corretto

Ci sono diverse funzioni che puoi usare: la funzione predefinita $.ajax({}); o le sue scorciatoie $.post();, $.getJSON();, ecc.

Quindi puoi semplicemente usare qualcosa come il seguente - utilizzando i metodi dell'oggetto success/fail.

( function( $, plugin ) {
    "use strict";

    $.ajax( {
        url : plugin.ajaxURl,
        data : {
            // altri dati
        },
        // Assumiamo che tu risponda con un wp_send_json_success/error() corretto nel callback PHP.
        dataType : "json",

        // Trasformazione della richiesta possibile qui.
        beforeSend : function( xhr ) {
            // Esempio:
            // xhr.overrideMimeType( 'application/json' );
        },

        // I gestori effettivi
        success : function( data, textStatus, jqXHR ) {
            // Gestisci la trasformazione dei dati o la manipolazione del DOM qui.
        },
        error : function( jqXHR, textStatus, errorThrown ) {
            // silenzioso: Registra l'errore
            console.info( errorThrown );
            // rumoroso: Lancia un'eccezione
            throw errorThrown;
        }
    } );
} )( jQuery, pluginObject || {} );

Se vuoi andare più in profondità e fare le cose davvero nel modo giusto, dovrai usare il method chaining. (C'è ancora spazio per miglioramenti).

( function( $, plugin ) {
    "use strict";

    $.ajax( {
        url : plugin.ajaxURl,
        data : {
            // altri dati
        },
    } )
        .done( function( data ) {
            // Gestisce solo risposte di successo
        } )
        .fail( function( reason ) {
            // Gestisce solo errori
            console.debug( reason );
        } )
        .always( function( data, textStatus, response ) {
            // Se vuoi separare manualmente le cose
            // response diventa errorThrown/reason OPPURE jqXHR in caso di successo
        } )
        .then( function( data, textStatus, response ) {
            // Se lavori con una deferred.promise, usa questo metodo
            // Di nuovo, dovrai separare manualmente successo/errore
        } );
} )( jQuery, pluginObject || {} );

Nota: Per esempi migliori del wrapper attorno al callback, dai un'occhiata a commonjs o AMD e alle loro differenze.

Aspettare altre risposte AJAX

La parte interessante - e più potente - di tutta la gestione AJAX di jQuery (e altre librerie) è come aspettare che A sia terminato per poi avviare B e la sua elaborazione. La risposta è il caricamento "deferred" e le "promises".

Aggiungerò un esempio veloce. Dovresti forse pensare di costruire un oggetto e separare le cose aggiungendole via this. all'oggetto, ma per un esempio il seguente dovrebbe essere sufficiente:

Esempio (A) Questo è fondamentalmente come lo faccio io. Dovrai riempire i pezzi da solo.

( function( $, plugin ) {
    "use strict";

    $.when(
        $.ajax( {
            url :  pluginURl,
            data : { /* ... */ }
        } )
           .done( function( data ) {
                // 2a chiamata terminata
           } )
           .fail( function( reason ) {
               console.info( reason );
           } )
        )
        // Di nuovo, potresti usare .done(). Vedi la documentazione di jQuery.
        .then( 
            // Successo
            function( response ) {
                // È andato a buon fine
                // In caso di più richieste, entrambe devono avere successo
            },
            // Fallimento
            function( resons ) {
                // Ha generato un errore
                // in caso di errori multipli, lancia il primo
            },
        );
} )( jQuery, pluginObject || {} );

Esempio (B) Non l'ho mai provato così, ma dovrebbe funzionare comunque. Più facile da leggere, ma preferisco le promesse risolte con $.when().

( function( $, plugin ) {
    "use strict";

    $.ajax( {
        url : plugin.ajaxURl,
        data : {
            // altri dati
        }
    } )
        .done( function( data ) {
            // Gestisce solo risposte di successo
        } )
        .fail( function( reason ) {
            console.info( reason );
        } )
        // Promise terminata:
        .then( function( data ) {
            $.ajax( {
                url :  pluginURl,
                data : { /* ... */ }
            } )
                .done( function( data ) {
                    // 2a chiamata terminata
                } )
                .fail( function( reason ) {
                    console.info( reason );
                } );
        } );
} )( jQuery, pluginObject || {} );

Se vuoi approfondire ancora di più, leggi la documentazione su deferred e then.

async/ await

MODIFICA Poiché questa risposta riceve molta attenzione nel corso degli anni e ha già 8 anni, dai un'occhiata al seguente snippet.

Tieni presente che async/await lavora ancora con le Promises. È solo zucchero sintattico. Tieni anche presente a cosa si riferisce this quando usi funzioni abbreviate come visto in handlerB().

Questo funzionerà anche con jQuery.

( function( $, plugin ) {
    const handlerA = async function( plugin ) {
        try {
            let res = await $.ajax( {
                url : plugin.ajaxURl,
                data : { /* alcuni dati */ }
            } )
                .done( function( data ) {
                    // Gestisce solo risposte di successo
                } )
                .fail( function( reason ) {
                    console.error( reason );
                } )
            return res;
        } catch ( err ) {
            console.error( err )
        }
    }
    const handlerB = async data => { /* un'altra richiesta AJAX */ }

    // Esegui
    // …aspetta…
    let $resultA = await handlerA( plugin )
    // Ora esegui B
    let $resultB = await handlerB( $resultA )

    // Fai qualcosa con $resultB

} )( jQuery, pluginObject || {} );
14 ott 2013 16:28:02
Commenti

In realtà non sto utilizzando alcun plugin. Una semplice chiamata AJAX di WordPress. Per quanto riguarda il problema del ritardo del server - Firebug mostra che la richiesta AJAX è completata senza dati ricevuti. Lasciami analizzare la tua risposta più in dettaglio.

Istiaque Ahmed Istiaque Ahmed
14 ott 2013 17:32:08

@IstiaqueAhmed La descrizione sopra non è pensata per essere un plugin. Solo la base per scrivere il tuo plugin (o, nel caso in cui non ti interessi la separazione delle responsabilità, il tuo tema).

kaiser kaiser
14 ott 2013 17:38:47

Grazie, questo è stato di grande aiuto in un progetto recente. Ho già votato positivamente molto tempo fa ;-) Volevo anche solo menzionare che le callback success, error, complete sono ora deprecate a favore delle promise callback menzionate nella risposta.

birgire birgire
14 ago 2015 17:52:20

@birgire Per favore [modifica] la risposta. Ho verificato e solo la prima parte è ora deprecata. Grazie in anticipo e grazie per le gentili parole :)

kaiser kaiser
15 ago 2015 14:05:16

Questa risposta è scritta in modo bellissimo. +1

Ahmed Alhallag Ahmed Alhallag
21 lug 2021 20:19:04

@kaiser negli esempi 'In attesa di altre risposte AJAX' A e B, dove si trovano esattamente le seconde chiamate ajax? Non riesco a vedere una seconda chiamata ajax nell'Esempio A.

HappyCoding HappyCoding
31 dic 2021 18:17:49

@HappyCoding vedi constant handlerB

kaiser kaiser
6 gen 2022 16:02:16
Mostra i restanti 2 commenti
0

Per eseguire una richiesta AJAX dopo il completamento di un'altra richiesta AJAX, devi aggiungere la seguente riga:

    async: false,

Ovvero, devi aggiungere async: false nel metodo ajax come mostrato di seguito:

$.ajax( {
    url : base_url+"/wp-admin/admin-ajax.php",
    type : 'GET',
    async: false,
9 gen 2019 07:11:42