首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 實現即時進度條效果:原理、代碼與最佳實踐

     編輯:PHP 綜合知識

前言

在長時間運行的 PHP 任務(如資料採集、批量匯入、報表生成)中,即時在瀏覽器顯示進度條能大幅提升用戶體驗。本文解析基於 Output Buffering + JavaScript 的經典實現原理,提供完整可運行代碼,並討論現代替代方案。

核心原理

  1. 關閉輸出緩衝:ob_end_clean() 確保內容立即發送。
  2. 分塊輸出 HTML/JS:先輸出進度條骨架,再循環輸出 <script>updateProgress(...);</script>。
  3. 強制刷新:每次迭代呼叫 flush() 將緩衝區推送給瀏覽器。
  4. 瀏覽器端 JS 更新 DOM:根據寬度/百分比動態修改進度條樣式。

完整實現代碼

<?php
// 防止腳本超時
set_time_limit(0);

// 清空並關閉輸出緩衝
ob_end_clean();

// 模擬資料源
$total = 188;
$users = array_map(function($i) { return "User_{$i}"; }, range(1, $total));

// 進度條參數
$width = 500;                 // 總寬度(px)
$pixPerItem = $width / $total; // 每項佔寬度
$progress = 0;

// 輸出頁面骨架
?>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>PHP 即時進度條演示</title>
    <style>
        body { font-family: Tahoma, sans-serif; font-size: 9pt; margin: 50px auto; }
        #container { width: <?= $width + 8 ?>px; border: 1px solid #999; background: #f0f0f0; padding: 8px; }
        #bar-bg { width: <?= $width ?>px; border: 1px solid navy; background: #fff; }
        #progress { height: 16px; background: #ffcc66; width: 0; text-align: center; }
        #status { margin-top: 8px; }
        #percent { position: relative; top: -30px; text-align: center; font-weight: bold; font-size: 8pt; }
    </style>
</head>
<body>
    <div id="container">
        <div id="bar-bg"><div id="progress"></div></div>
        <div id="status"></div>
        <div id="percent">0%</div>
    </div>
    <script>
        function updateProgress(msg, width) {
            document.getElementById('status').innerHTML = msg;
            document.getElementById('progress').style.width = width + 'px';
            document.getElementById('percent').innerHTML = Math.round(width / <?= $width ?> * 100) + '%';
        }
    </script>
<?php
// 關鍵:先發送骨架
flush();

// 處理循環
foreach ($users as $user) {
    // 模擬耗時操作(實際替換為真實業務邏輯)
    usleep(20000); // 20ms

    $progress += $pixPerItem;
    $currWidth = min($width, (int)$progress);

    // 輸出 JS 更新進度
    echo '<script>updateProgress("正在處理: ' . addslashes($user) . ' ...", ' . $currWidth . ');</script>';
    flush(); // 強制推送
}

// 完成
echo '<script>updateProgress("處理完成!", ' . $width . ');</script>';
flush();
?>
</body>
</html>

關鍵點詳解

1. 輸出緩衝控制

ob_end_clean() 關閉 PHP 預設緩衝;若使用 Nginx + FastCGI,還需在 Nginx 配置中關閉 proxy_buffering off; 並確保 fastcgi_buffering off;,否則進度條會一次性跳至 100%。

2. flush() 的限制

  • 僅刷新 PHP 內部緩衝區,不保證瀏覽器立即渲染。
  • 部分防毒軟體、代理伺服器會緩衝響應,導致延遲。
  • HTTP/2 或 gzip 壓縮可能干擾分塊傳輸。

3. 現代替代方案

方案優點缺點
WebSocket / Server-Sent Events (SSE)真雙向/單向推送,低延遲,支援多任務並行需額外服務,實現較複雜
AJAX 輪詢簡單,相容性好頻繁請求增加伺服器負載
前端模擬進度零後端改動,體驗尚可非真實進度,僅適用於固定流程
Laravel Horizon / Symfony Messenger + Redis企業級隊列監控,內建儀表板需引入框架生態

生產環境建議

  • 將耗時任務放入隊列,前端通過 AJAX/SSE 查詢進度狀態(存於 Redis/DB)。
  • 避免在 Web 請求中直接運行超長腳本,防止閘道超時。
  • 若必須同步輸出,請測試目標瀏覽器與代理環境的緩衝行為。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved