Выполнение одного AJAX запроса после завершения другого AJAX запроса

14 окт. 2013 г., 12:08:59
Просмотры: 177K
Голосов: 6

Один JS файл выполняет ajax запрос. В функции success этого ajax запроса выполняется другой AJAX запрос. Второй запрос проверяет, был ли уже зарегистрирован email. Если email уже зарегистрирован, то второй AJAX запрос не получает возвращаемых данных, как показано в Firebug и консоли Chrome. Однако тот же код прекрасно работает на localhost, а указанная проблема возникает ТОЛЬКО на рабочем сервере.

Размещенная страница находится по адресу http://twmobilefitness.com/signup/. Проблема возникает при нажатии на ссылку 'Register Now' в конце. Чтобы воспроизвести проблему, нужно попытаться зарегистрироваться дважды с одним и тем же email адресом.

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">Имя пользователя недоступно</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 уже используется</span>' );
                    } else if ( parseInt( result_email ) == 1 ) {
                        $( ".result" ).html( '' );      
                        $( ".signup_div" ).hide();
                        $( ".signup_emergency_contact" ).show();
                    }
                }
            } );
        }
    }   
} );    

functions.php содержит:

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();
}

Как заставить код работать на рабочем сервере?

0
Все ответы на вопрос 2
7
14

То, с чем вы столкнулись (AJAX работает локально, но не на сервере) — это проблема задержки. Локально всё работает настолько быстро, что вы не видите своей проблемы. Коротко говоря, вот в чём проблема:

AJAX-колбэк (A) выполняется > AJAX-колбэк (B) не знает, что ему нужно ждать завершения (A) > На локальной установке вы не видите проблему, так как (A) завершается слишком быстро.

Таким образом, вам нужно найти способ сообщить колбэку (B), что он должен дождаться выполнения (A). Вот как это сделать:

Регистрация скриптов и передача данных из PHP в JS

Правильно зарегистрируйте и подключите скрипты, а также передайте данные: оберните это в функцию или метод и подключите к wp_enqueue_scripts (публичная часть/темы), login_enqueue_scripts (пароли/вход/регистрация) или admin_enqueue_scripts. Затем используйте wp_localize_script(), чтобы передать данные из PHP в JS и сделать их доступными.

add_action( 'admin_enqueue_scripts', 'wpse118772jsObject' );
function wpse118772jsObject()
{
    $scriptHandle = 'custom-script-name';
    // Лучше разделить на отдельные функции или методы
    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(
                        // пользовательские данные здесь
                ),
        ),
    );
}

Правильное использование jQuery AJAX

Есть несколько функций, которые можно использовать: стандартная $.ajax({}); или её сокращённые версии $.post();, $.getJSON(); и т. д.

Вы можете использовать что-то вроде следующего — с помощью методов объекта success/fail.

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

    $.ajax( {
        url : plugin.ajaxURl,
        data : {
            // другие данные
        },
        // Предполагаем, что PHP-колбэк возвращает ответ через wp_send_json_success/error().
        dataType : "json",

        // Преобразование запроса возможно здесь.
        beforeSend : function( xhr ) {
            // Пример:
            // xhr.overrideMimeType( 'application/json' );
        },

        // Обработчики
        success : function( data, textStatus, jqXHR ) {
            // Обработка данных или манипуляции с DOM.
        },
        error : function( jqXHR, textStatus, errorThrown ) {
            // Тихий режим: логирование ошибки
            console.info( errorThrown );
            // Громкий режим: выброс исключения
            throw errorThrown;
        }
    } );
} )( jQuery, pluginObject || {} );

Если вы хотите углубиться и делать всё действительно правильно, вам придётся использовать цепочки методов. (Здесь ещё есть место для улучшения.)

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

    $.ajax( {
        url : plugin.ajaxURl,
        data : {
            // другие данные
        },
    } )
        .done( function( data ) {
            // Обработка успешных ответов
        } )
        .fail( function( reason ) {
            // Обработка ошибок
            console.debug( reason );
        } )
        .always( function( data, textStatus, response ) {
            // Если нужно вручную разделить данные
            // response будет errorThrown/reason или jqXHR в случае успеха
        } )
        .then( function( data, textStatus, response ) {
            // При работе с deferred.promise используйте этот метод
            // Снова нужно вручную разделять успех/ошибку
        } );
} )( jQuery, pluginObject || {} );

Примечание: Для лучших примеров обёртки вокруг колбэка посмотрите разницу между CommonJS и AMD.

Ожидание других AJAX-запросов

Самый интересный и мощный аспект работы с AJAX в jQuery (и других библиотеках) — это вопрос о том, как дождаться завершения A, прежде чем запускать B и его обработку. Ответ — использование "отложенной" загрузки и "обещаний" (promises).

Приведу быстрый пример. Возможно, стоит подумать о создании объекта и разделении логики через this., но для примера этого будет достаточно:

Пример (A) Вот как я обычно делаю. Остальное вам нужно заполнить самостоятельно.

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

    $.when(
        $.ajax( {
            url :  pluginURl,
            data : { /* ... */ }
        } )
           .done( function( data ) {
                // 2-й запрос завершён
           } )
           .fail( function( reason ) {
               console.info( reason );
           } )
        )
        // Можно также использовать .done(). См. документацию jQuery.
        .then( 
            // Успех
            function( response ) {
                // Успешный ответ
                // Если запросов несколько, оба должны быть успешными
            },
            // Ошибка
            function( resons ) {
                // Произошла ошибка
                // Если ошибок несколько, выбрасывается первая
            },
        );
} )( jQuery, pluginObject || {} );

Пример (B) Я сам так не пробовал, но это должно работать. Легче читается, но мне больше нравится $.when() с разрешёнными обещаниями.

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

    $.ajax( {
        url : plugin.ajaxURl,
        data : {
            // другие данные
        }
    } )
        .done( function( data ) {
            // Обработка успешных ответов
        } )
        .fail( function( reason ) {
            console.info( reason );
        } )
        // Обещание выполнено:
        .then( function( data ) {
            $.ajax( {
                url :  pluginURl,
                data : { /* ... */ }
            } )
                .done( function( data ) {
                    // 2-й запрос завершён
                } )
                .fail( function( reason ) {
                    console.info( reason );
                } );
        } );
} )( jQuery, pluginObject || {} );

Если хотите углубиться, изучите документацию по deferred и then.

async/ await

ОБНОВЛЕНИЕ Так как этот ответ привлекает внимание уже 8 лет, обратите внимание на следующий пример.

Помните, что async/await всё равно работает с обещаниями (Promises). Это просто синтаксический сахар. Также учитывайте, на что ссылается this при использовании стрелочных функций, как в handlerB().

Это будет работать даже с jQuery.

( function( $, plugin ) {
    const handlerA = async function( plugin ) {
        try {
            let res = await $.ajax( {
                url : plugin.ajaxURl,
                data : { /* какие-то данные */ }
            } )
                .done( function( data ) {
                    // Обработка успешных ответов
                } )
                .fail( function( reason ) {
                    console.error( reason );
                } )
            return res;
        } catch ( err ) {
            console.error( err )
        }
    }
    const handlerB = async data => { /* ещё один AJAX-запрос */ }

    // Выполнение
    // …ожидание…
    let $resultA = await handlerA( plugin )
    // Теперь выполняем B
    let $resultB = await handlerB( $resultA )

    // Делаем что-то с $resultB

} )( jQuery, pluginObject || {} );
14 окт. 2013 г. 16:28:02
Комментарии

На самом деле я не использую никаких плагинов. Простой AJAX-вызов в WordPress. Что касается проблемы задержки сервера - Firebug показывает, что AJAX-запрос завершен, но данных не получено. Позвольте мне подробнее изучить ваш ответ.

Istiaque Ahmed Istiaque Ahmed
14 окт. 2013 г. 17:32:08

@IstiaqueAhmed Это описание не предназначено для какого-то конкретного плагина. Это просто основа для написания собственного плагина (или, если вас не волнует разделение ответственности, вашей собственной темы).

kaiser kaiser
14 окт. 2013 г. 17:38:47

Спасибо, это очень помогло в недавнем проекте. Уже давно проголосовал за ;-) Также хотел упомянуть, что обратные вызовы success, error, complete теперь считаются устаревшими в пользу обещаний (promises), упомянутых в ответе.

birgire birgire
14 авг. 2015 г. 17:52:20

@birgire Пожалуйста, [отредактируйте] ответ. Я проверил и только первая часть теперь устарела. Заранее спасибо и спасибо за добрые слова :)

kaiser kaiser
15 авг. 2015 г. 14:05:16

Этот ответ так красиво написан. +1

Ahmed Alhallag Ahmed Alhallag
21 июл. 2021 г. 20:19:04

@kaiser в примерах 'Ожидание других AJAX-ответов' A и B, где именно находятся вторые ajax-вызовы? Я не вижу второго ajax-вызова в Примере A.

HappyCoding HappyCoding
31 дек. 2021 г. 18:17:49

@HappyCoding смотри constant handlerB

kaiser kaiser
6 янв. 2022 г. 16:02:16
Показать остальные 2 комментариев
0

Для выполнения одного AJAX-запроса после завершения другого AJAX-запроса необходимо добавить следующую строку:

 
    async: false,

То есть, вам нужно добавить async: false в метод ajax, как показано ниже:

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