You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何跟踪while循环进度,实现后台加载并完成后显示结果?

Got it, let's break down how to add background processing with real-time progress tracking to your database loop. Here's a practical, step-by-step solution that keeps users informed without leaving them staring at a frozen screen:

1. Why Your Current Setup Won't Work (And What to Do Instead)

Right now, your synchronous loop blocks the browser until all 88 entries are processed—this is why users see no progress for 35-40 seconds. We need to split the work into two parts:

  • A backend that handles processing in the background
  • A frontend that polls for progress updates and displays them
2. Backend Setup: Split into 3 Scripts

We'll use PHP sessions to track progress (you could also use a cache like Redis for scaling, but sessions work for most small-scale use cases).

Script 1: Initialize the Process (start_process.php)

This script sets up the progress tracking and starts the background processing:

<?php
session_start();

// Connect to database to get total entry count
$conn = mysqli_connect('localhost', 'your_user', 'your_pass', 'your_db');
$totalQuery = mysqli_query($conn, "SELECT COUNT(*) AS total FROM your_table");
$totalRow = mysqli_fetch_assoc($totalQuery);
$totalItems = $totalRow['total'];
mysqli_close($conn);

// Initialize progress in session
$_SESSION['processing'] = [
    'total' => $totalItems,
    'completed' => 0,
    'results' => [],
    'status' => 'running'
];

// Start background processing (using exec to avoid blocking the browser)
// Note: Adjust the path to process_batch.php as needed
exec("php /path/to/process_batch.php > /dev/null 2>&1 &");

// Return total count to frontend
header('Content-Type: application/json');
echo json_encode(['total' => $totalItems]);
?>

Script 2: Process Entries in Batches (process_batch.php)

This script runs in the background, processes entries one by one, and updates the session progress:

<?php
session_start();

// Exit if no process is initialized
if (!isset($_SESSION['processing'])) exit;

$conn = mysqli_connect('localhost', 'your_user', 'your_pass', 'your_db');

// Track offset to avoid reprocessing entries
if (!isset($_SESSION['processing']['offset'])) {
    $_SESSION['processing']['offset'] = 0;
}

// Process 1 entry per run (adjust to batch size if you want faster progress updates)
$limit = 1;
$query = mysqli_query($conn, "SELECT * FROM your_table LIMIT {$_SESSION['processing']['offset']}, $limit");

while ($row = mysqli_fetch_assoc($query)) {
    // Call external site (use cURL for better error handling)
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "https://external-site.com/api?param=" . urlencode($row['your_column']));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $externalData = curl_exec($ch);
    curl_close($ch);

    // Store result and update progress
    $_SESSION['processing']['results'][] = [
        'entry_id' => $row['id'],
        'external_data' => $externalData
    ];
    $_SESSION['processing']['completed']++;
    $_SESSION['processing']['offset']++;

    // Release session lock to let frontend read progress
    session_write_close();
    session_start();
}

mysqli_close($conn);

// Mark process as done if all entries are processed
if ($_SESSION['processing']['completed'] >= $_SESSION['processing']['total']) {
    $_SESSION['processing']['status'] = 'done';
} else {
    // Re-run the script to process next entry (loop until done)
    exec("php /path/to/process_batch.php > /dev/null 2>&1 &");
}
?>

Script 3: Get Current Progress (get_progress.php)

This script returns the latest progress data to the frontend:

<?php
session_start();
header('Content-Type: application/json');

if (!isset($_SESSION['processing'])) {
    echo json_encode(['error' => 'No process started']);
    exit;
}

echo json_encode($_SESSION['processing']);
?>
3. Frontend: Build a Progress UI with JavaScript

Create a simple interface that starts the process, polls for updates, and shows results when done:

HTML

<div class="progress-wrapper">
    <div class="progress-bar" id="progressBar"></div>
    <p id="progressText">0% Complete</p>
</div>
<div id="results" style="display: none;">
    <h2>Processing Complete!</h2>
    <ul id="resultsList"></ul>
</div>
<button onclick="startProcessing()" id="startBtn">Start Processing</button>

CSS

.progress-wrapper {
    width: 100%;
    height: 24px;
    border: 1px solid #ddd;
    border-radius: 12px;
    overflow: hidden;
    margin: 20px 0;
}
.progress-bar {
    height: 100%;
    width: 0%;
    background-color: #2ecc71;
    transition: width 0.3s ease;
}

JavaScript

function startProcessing() {
    document.getElementById('startBtn').disabled = true;
    
    // Initialize process
    fetch('start_process.php')
        .then(res => res.json())
        .then(data => {
            if (data.total) {
                // Start polling for progress
                pollProgress();
            }
        });
}

function pollProgress() {
    fetch('get_progress.php')
        .then(res => res.json())
        .then(data => {
            if (data.status === 'done') {
                // Update to 100% and show results
                updateProgress(100);
                displayResults(data.results);
                // Cleanup session
                fetch('cleanup_session.php'); // Optional: create a script to unset $_SESSION['processing']
            } else {
                const percent = Math.round((data.completed / data.total) * 100);
                updateProgress(percent);
                // Poll again after 500ms (matches your per-entry processing time)
                setTimeout(pollProgress, 500);
            }
        });
}

function updateProgress(percent) {
    const bar = document.getElementById('progressBar');
    const text = document.getElementById('progressText');
    bar.style.width = `${percent}%`;
    text.textContent = `${percent}% Complete (${data.completed}/${data.total})`;
}

function displayResults(results) {
    const resultsContainer = document.getElementById('results');
    const resultsList = document.getElementById('resultsList');
    
    resultsContainer.style.display = 'block';
    results.forEach(result => {
        const li = document.createElement('li');
        li.textContent = `Entry ${result.entry_id}: ${result.external_data}`;
        resultsList.appendChild(li);
    });
}
4. Key Notes for Reliability
  • Session Locking: Use session_write_close() after updating progress to prevent the frontend from waiting for the session lock to release.
  • Error Handling: Add try/catch blocks around external API calls to handle failures without breaking the entire process.
  • Batch Size: If you want fewer backend calls, increase the $limit in process_batch.php (e.g., process 5 entries at once) and adjust the poll interval accordingly.
  • Cleanup: Add a cleanup_session.php script to clear the session data after processing finishes, so users can run the process again.

内容的提问来源于stack exchange,提问作者Born2DoubleUp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:51:42