Проблема параллелизма при обновлении метаданных Wordpress через ajax

Вот сценарий: я создаю плагин Wordpress для управления некоторыми исследованиями, в которых я участвую. Администратор проекта может загрузить файл csv из интерфейса администратора WP. На стороне клиента, когда файл загружается, он просматривает каждую строку файла, извлекает необходимую информацию о пользователях, а затем выполняет вызов AJAX для добавления участника в проект. Я решил проанализировать файл csv на стороне клиента и отправить запросы ajax один за другим, чтобы я мог обновлять индикатор выполнения по мере каждого возврата. Яваскрипт выглядит так:

$( '#csv_upload_button' ).click( function() {
    // declare the necessary variables
    var f = $( '#csv_file_input' )[0].files[0],
        fr = new FileReader,
        rows, headers, dialog, count, remaining;
    // when the file loads
    fr.onload = function() {
        // get the rows, the count, number remaining to process, and headers
        rows = fr.result.split( "\n" );
        remaining = count = rows.length - 1; // -1 to account for header row
        headers = $.trim( rows[0] ).split( ',' );
        // create the dialog box to show the progress bar
        dialog = $( '<div></div>' )
                    .html( 
                        '<p>Loading...</p>' +
                        '<p><progress id="csv_upload_progress" max="' + count + 
                        '" min="0" value="0"></p>' )
                    .dialog( { modal: true; } );
        // then for each row in the file
        $( rows ).each( function( i, r ) {
            // create an object to hold the data
            var data = {}, row = $.trim( r ).split( ',' ), j;
            if ( i > 0 ) { // data starts on the second row
                // map the data into our object
                for ( j = 0; j < headers.length; j++ ) {
                    data[ headers[ j ] ] = row[ j ];
                }
                // send it to the server
                $.post(
                    ajaxurl, 
                    { 
                        action: 'import_panel_member', 
                        data: data, 
                        postid: $( '#post_ID' ).val() 
                    }, 
                    function( result ) {
                        var prog = $( '#csv_upload_progress' );
                        prog.attr( 'value', prog.attr( 'value' ) + 1 );
                        if ( 0 == --remaining ) {
                            // stuff to do when everything has been loaded
                        }
                    }
                );
            }
        });
    };
    // read the csv file
    fr.readAsText( f );
});

PHP выглядит примерно так:

function import_panel_member() {
    header( 'content-type: application/json' );
    // get the variables sent from the client
    $postid = $_POST[ 'postid' ];
    $data   = $_POST[ 'data'   ];
    /*
     * ...do other things involving talking to a 3rd party server...
     */
    // get the WP meta data variable to be updated
    $participants = get_post_meta( $postid, '_project_participants', true );
    // modify it
    $participants[] = $data;
    // update the database
    update_post_meta( $postid, '_project_participants', $participants );
    // return a message to the client
    echo json_encode( (object) array( 'success' => 1, 'message' => 'added' ) );
    exit;
}

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

  1. Измените $.post() на $.ajax() и установите async: false
    Это работает, но намного медленнее (из-за синхронных вызовов) и по какой-то причине не позволяет моему диалоговому окну отображаться до тех пор, пока не закончатся все вызовы ajax.
  2. Загрузите весь CSV-файл на сервер и обработайте его там
    Вместо того, чтобы анализировать CSV-файл на стороне клиента. Это тоже работает, но я не думаю, что смогу получить промежуточную обратную связь от сервера, которую я могу использовать для обновления индикатора выполнения. Этот запрос может занять довольно много времени, и я не хочу, чтобы пользователи «отказались» от запроса до его завершения. При этом иногда сервер никогда не отвечает на вызов ajax.

Так что, возможно, я жадный и просто хочу свой пирог и съесть его тоже. Как я могу воспользоваться преимуществами скорости асинхронных запросов, которые дают мне возможность давать обратную связь пользователю с помощью индикатора выполнения, но при этом не напортачить с проблемами параллелизма на сервере?


person morphatic    schedule 31.10.2012    source источник


Ответы (1)


Я понял. Ответ был гибридом двух методов. Я могу использовать серию вызовов $.post(), чтобы сделать то, что лучше работает в асинхронном режиме, а затем загрузить весь csv, чтобы сделать то, что лучше работает в синхронном режиме. Никогда бы не понял этого, не набрав все объяснение в SO!

person morphatic    schedule 31.10.2012
comment
Вы также можете загрузить все сразу и использовать API Transients, чтобы отслеживать процесс. Затем клиент может опросить сервер и получить статус обработки на основе значения в кеше. - person doublesharp; 31.10.2012