PHP、Smarty、ケータイサイトについて発信中。書籍 「Smarty動的webサイト構築入門」(技術評論社) 好評発売中
RSS icon Home icon
  • 処理時間が長いとき、すばやくページ表示したい(4)


     フォーム送信後、サーバ側の処理時間が長いとき、なかなか画面が変わらないことがあります。サーバ側の処理時間が長いときでも、すばやくページを表示するいくつかの方法について説明します。

    (4) 難しい方法 (プログレスバーを表示する)

     今回は、10000回のループ処理で時間がかかっている場合に、ループ処理を複数のリクエストに分けます。データベースのクエリー1回で時間がかかっている場合には、今回の方法は使えません。

     人が10000件の一覧を見るときに例えると、10000件を1ページで見るのが、前回までの方法。100件づつ100ページに分けて、次へ次へで見ていくのが、今回の方法です。

     ページ遷移は form.html ⇒ task.php ⇒ thanks.html  となります。ただし、task.phpは、1回だけではなく、task.php   ⇒ task.php?rcd_pos=0 ⇒ task.php?rcd_pos=200 と何回も呼ばれます。

     次の例は、0.01秒 x 10000件の処理です。約2秒おきに進捗状況を表示します。

     4_1 4_2

     いろいろな実装方法があります。今回の実装では、セッション変数を使いました。クエリー変数 $_GET['rcd_pos']はループ処理には利用していません。また、100回づつで分けるのではなく、2秒ごとに分けました。

    <?php
    /*
     * task.php?rcd_pos=123
     */
    define( 'MAX_PROCESS_SEC', 2 );
    session_start();
    
    if ( ! isset($_GET['rcd_pos']) ) {
     $_SESSION['rcd_cnt'] = 10000;
     $_SESSION['rcd_pos'] = 0;
     $_SESSION['time_st'] = time();
    } else {
     $t0 = time();
    
     for ( ; $_SESSION['rcd_pos'] < $_SESSION['rcd_cnt']; ++$_SESSION['rcd_pos'] ) {
      if ( MAX_PROCESS_SEC <= time() - $t0 ) {
       break;
      }
      usleep( 10000 ); // 0.01秒
     }
    }
    
    if ( $_SESSION['rcd_cnt'] <= $_SESSION['rcd_pos'] ) {
     $url = "thanks.html";
    } else {
     $url = "task.php?rcd_pos=" . $_SESSION['rcd_pos'];
    }
    
    $tpl['rcd_cnt'] = $_SESSION['rcd_cnt'];
    $tpl['rcd_pos'] = $_SESSION['rcd_pos'];
    $tpl['elapsed_sec'] = time() - $_SESSION['time_st'];
    $tpl['percent'] = floor(100 * $_SESSION['rcd_pos'] / $_SESSION['rcd_cnt']);
    ?>
    <html>
    <head>
    <meta http-equiv="refresh" content="0; url=<?php echo $url?>" />
    <style>
    .frame {
     border: 1px solid #000;
     width: 400px;
     height: 50px;
    }
    .progress {
     width: <?php echo $tpl['percent'] ?>%;
     height: 50px;
     background: #00f;
    }
    </style>
    </head>
    <body>
    処理中です<br />
    全件数 : <?php echo $tpl['rcd_cnt'] ?><br />
    処理済み: <?php echo $tpl['rcd_pos'] ?><br />
    経過時間: <?php echo $tpl['elapsed_sec'] ?>sec<br />
    
    <div class="frame">
      <div class="progress">
        <br />
      </div>
    </div>

     ブラウザがリクエストしなければ、次の処理へ進まないので、途中停止が簡単です。サーバ側にキャンセルという仕組みを用意する必要がありません。ブラウザの[中止]ボタン、[閉じる]ボタン、キャンセルページへのリンク、どれでも途中停止します。

    実験ページ(4)

    2009-04-12 aoki No comments 02.PHP

    Leave a reply