Как задержать запуск функции PHP в цикле jQuery Ajax? - PullRequest
0 голосов
/ 17 декабря 2018

У меня есть скрипт PHP, который временно загружает CSV.Одна страница перезагрузит данные CSV, полученные из $_FILES и преобразованные в массив JSON.

Затем я перебираю строки CSV, используя $.each.

Для каждой строки, которую я делаюAJAX-вызов функции PHP, которая устанавливает некоторые данные отслеживания заказа и отправляет электронное письмо.

Из-за ограничений электронной почты я хочу добавить задержку между каждой итерацией цикла.Однако я попытался сделать это с помощью установленного тайм-аута в JavaScript, который не работал, а также попытался добавить функцию ожидания PHP до того, как письмо будет отправлено.

Ни одна из этих операций, письма по-прежнему отправляются по адресув то же время без задержки.

Появляются все запросы, которые я делаю, независимо от добавляемых задержек, обрабатываются одновременно.

Как я могу гарантировать, что отправка электронной почты задерживается?

jQuery ($ csv_rows - это данные CSV, которые были только что загружены)

<script>

    // Get CSV Rows into JSON array

    var csvRows = '<?php echo json_encode( $csv_rows ); ?>';
    var csvRows = ( jQuery.parseJSON( csvRows ) );

    // Loop through each row

    $.each( csvRows, function( key, value ) {

        // Split row into array exploded by comma

        row = value.toString().split( ',' );

        // Get column values

        order = row[0];
        courier = row[1];
        tracking = row[2];

        // AJAX

        var data = {
            'action': 'shd_tracking_import',
            'order': order,
            'courier': courier,
            'tracking': tracking,
        };

        // Do the ajax

        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: data,
            success: function( response ) {
                $( '#shd-import-results p' ).hide();
                if( response !== '0' ) {
                    $( '#shd-import-results ul' ).append( response );
                    importedCount = parseInt( $( '#shd-import-progress span' ).text() );
                    $( '#shd-import-progress span' ).text( importedCount + 1 );
                } else {
                    $( '<p>Error importing. Please ensure CSV meets requirements.</p>' ).appendTo( '#shd-import-results' );
                }
            }
        });

    });

</script>

PHP (это действие shd_tracking_import, на которое ссылается AJAX)

if( isset( $_POST['order'] ) && isset( $_POST['courier'] ) && isset( $_POST['tracking'] ) ) {

    // Delay (due to their Office 365 limits)

    usleep( 4000000 ); // 4 Seconds (usleep used as sleep cannot contain fractions, usleep is microseconds, this was 2.5 seconds hence using usleep)

    // My mailing function is here (which works just not delayed)

    echo 'Done';

} else {

    echo '0';

}

exit;

Ответы [ 4 ]

0 голосов
/ 18 декабря 2018

После просмотра ответов я решил взглянуть на это немного по-другому, так как я не хотел вдаваться в сеансы и не мог использовать .promise () на $ .each.Поэтому я переписал код следующим образом.

Это работает, получая общее количество строк из CSV, запуская AJAX один раз, затем я использую .done () на ajax для повторного запуска вызова AJAX до тех пор, пока он не пройдетвсе строки, и это работает, как я хотел.

<script>

    // Get CSV Rows into JSON array

    var csvRows = '<?php echo json_encode( $csv_rows ); ?>';
    var csvRows = ( jQuery.parseJSON( csvRows ) );
    var totalRows = csvRows.length - 1; // Minus 1 as starts 1, we need to start from 0 (e.g. for 4 rows this returns 4, when row 4 is actually 3 as starts from 0)

    // Do AJAX function

    function doAjax( $row ) {

        // Error

        var error = false;

        // Get row data

        order = csvRows[row][0];
        courier = csvRows[row][1];
        tracking = csvRows[row][2];

        // AJAX

        var data = {
            'action': 'shd_tracking_import',
            'order': order,
            'courier': courier,
            'tracking': tracking,
        };

        // Do the ajax

        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: data,
            success: function( response ) {
                $( '#shd-import-results p' ).hide();
                if( response !== '0' ) {
                    $( '#shd-import-results ul' ).append( response );
                    importedCount = parseInt( $( '#shd-import-progress span' ).text() );
                    $( '#shd-import-progress span' ).text( importedCount + 1 );
                } else {
                    error = true;
                }
            }
        }).done( function() {

            if( error !== true ) {

                // When AJAX is done

                var dt = new Date();
                var time = dt.getHours() + ":" + dt.getMinutes() + ":" + dt.getSeconds();

                // Row number total

                row = row + 1;

                // If row number is less than or equal to the total row count, if not do nothing, no further call.

                if( row <= totalRows ) {

                    console.log( 'Next AJAX about to run @ ' + time );
                    doAjax( row );

                } else {

                    $( '<span> - Import complete.</span>' ).appendTo( '#shd-import-progress' );

                }

            } else {

                $( '<span> - Import failed, check CSV meets requirements.</span>' ).appendTo( '#shd-import-progress' );

            }

        });

    }

    // Start row at zero

    row = 0;

    // Do Ajax (once row is done next row will run same AJAX function until all rows done)

    doAjax( row );

</script>
0 голосов
/ 17 декабря 2018

Ваш скрипт запускает все экземпляры одновременно, и все они задерживаются на 4 секунды, но асинхронно.

Ваша задержка должна быть в JavaScript, чтобы вызывать PHP-файл каждые 4 секунды.

0 голосов
/ 17 декабря 2018

Хотя ответ Пиюша правильный, я бы все равно занимался этим сервером.Я понимаю, почему вы хотели бы видеть прогресс, и есть несколько вариантов.

Например:

<?php

$file = tempnam(__DIR__, 'csv-upload');
$fh = fopen($file, 'a+b');
foreach ($csv_rows as $row) {
    fputcsv($fh, $row);
}
fclose($fh);
$rowCount = count($csv_rows);
$file = str_replace(__DIR__, '', $file);

?>
<script>
    var csvTotal = <?= $rowCount; ?>,
        csvCount = 0,
        end = false
    ;

    var looper = requestTimeout(function () {
        if (end || csvCount >= csvTotal) {
            clearTimeout(looper);
            return;
        }

        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {'file': '<?= $file; ?>'},
            success: function (response) {
                response = JSON.parse(response);
                if (!response.success) {
                    end = true;
                    $('<p>' + response.msg + '</p>').appendTo('#shd-import-results');
                } else {
                    csvCount = response.msg;
                    $('#shd-import-progress span').text(csvCount);
                }
            }
        });
    }, 4000);

</script>

и ajax:

<?php

session_start();
ignore_user_abort(true);
set_time_limit(0);

//filename as unique key, so you can have mutiple queues at the same time
if (!isset($_POST['file'])) {
    echo json_encode([
        'success' => false,
        'msg' => 'File name required'
    ]);
    die();
}
$file = __DIR__ . $_POST['file'];
if (!file_exists($file)) {
    echo json_encode([
        'success' => false,
        'msg' => 'File does not excist'
    ]);
    die();
}


if (!isset($_SESSION['email_status'], $_SESSION['email_status'][$file])) {
    $fh = fopen($file, 'rb');
    $_SESSION['email_status'][$file] = 0;
    while ($row = fgetcsv($fh)) {
        $order = $row['order'];
        $courier = $row['courier'];
        $tracking = $row['tracking'];

        mail();
        $_SESSION['email_status'][$file]++;
        //4 seconds delaye
        usleep(4000);
    }
    fclose($fh);
    unlink($file);
} else {
    echo json_encode([
        'success' => false,
        'msg' => $_SESSION['email_status'][$file]
    ]);
}

Ссеанс будет только начать электронную почту один раз.проблема здесь заключается в том, что когда сеанс / куки очищаются, он запускает его снова, поэтому может быть лучше использовать другой механизм хранения (redis, или записать pid-файл или что-то нет), но это должно проиллюстрировать, что япытаясь достичь.

0 голосов
/ 17 декабря 2018

Вы можете использовать обещания в jquery, когда выполнение API завершится, тогда будет выполняться код обещание .

См. Пример

var div = $( "<div>" );

div.promise().done(function( arg1 ) {
  // Will fire right away and alert "true"
  alert( this === div && arg1 === div );
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...