首页 > 解决方案 > How to delay PHP function from triggering in a jQuery Ajax Loop?

问题描述

I have a PHP script which uploads a CSV temporarily. One page reload the CSV data is got from $_FILES and converted to a JSON array.

I then iterate through the CSV Rows using $.each.

For each row I am doing an AJAX call to a PHP function which sets some order tracking data and sends an email.

Due to email restrictions I want to add a delay between each loop iteration. However i have attempted to do this using a set time out in the JavaScript which didn't work and also attempted to add a PHP sleep function before the email gets sent.

Neither work, the emails still get sent at the same time with no delay.

It would appear all the requests I am making regardless of the delays I am adding are being processed at once.

How can I ensure the email sending is delayed?

jQuery ($csv_rows is the CSV data which was just uploaded)

<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 (this is the shd_tracking_import action referenced in 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;

标签: phpjqueryajax

解决方案


虽然 Piyush 的回答是正确的,但我仍然会做这个服务器时间。我理解您为什么希望看到进展,并且有一些选择。

例如:

<?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>

和阿贾克斯:

<?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]
    ]);
}

对于会话,它只会启动一次电子邮件。这里的问题是,当会话/cookies被清除时,它会再次运行它,所以最好使用不同的存储机制(redis,或者写一个pid文件或其他什么),但它应该说明我是什么试图达到。


推荐阅读