2012-02-16 49 views
7

私はプログレスバーに進み、ajaxリクエストとセッション変数を使って進行状況を更新しています。私のプログラムが多くの電子メールの送信など、時間のかかる操作を実行するときには、適切なセッション変数(進捗値を含む)を設定するだけです。この操作は、以下のコードで関数post()によって開始されます。PHPとAjaxを使ったプログレスバー

一方、2番目の関数ask()は500msごとにループで実行されます。現在の進行状況をリアルタイムで返します。そしてここに問題があります:ask()によって送られたすべてのリクエストは、post()関数が終了したリクエストを待っています。面白いのは、url/to/progressの代わりにgoogle.comのようなURLを設定した場合、それは私が望むものではないという点を除いてうまく動作するということです。つまり、その問題はサーバー側にあります。

重要なのかどうかわかりませんが、私はYii Frameworkを使用しています。

以下のすべてのコードは唯一のものですが、その唯一の目的は私の意図を示すことです。

ありがとうございます。

私の下手な英語のため申し訳ありません:)

表示一部:

<script type="text/javascript"> 
function ask() { 
    var d = new Date(); 
    var time = d.getTime(); 
    $.ajax({ 

    type: 'get', 
    url: '/url/to/progress' + '?time=' + time, 
    success: function(data) { 
     $("#progress").html(data); 
    } 
    }) 
} 

function post() { 
    var d = new Date(); 
    var time = d.getTime(); 

    $.ajax({ 
     type: 'post', 
     url: '/url/to/post' + '?time=' + time, 
     data: {"some": "data"}, 
     success: function(data) {alert(data)} 
    }); 
} 

$("#test").click(
    function() { 
    post(); 
    var progress = setInterval("ask();", 500); 
    } 
); 
</script> 

コントローラー部分:

public function actionPost($time) { 
    sleep(5); // time consuming operation 
    echo $time . ' : ' . microtime(); 
    exit; 
} 

public function actionProgress($time) { 
    echo $time . ' : ' . microtime(); 
    exit; 
} 
+0

あなたのサーバーからの応答は何ですか? dev tools> network> xhr requestsを確認してください –

答えて

9

私はここにあなたの問題は、セッションに関連していると思います。

スクリプトにオープンセッションがある場合、セッションファイルにロックが設定されています。つまり、同じセッションIDを使用する後続のリクエストは、最初のスクリプトがセッションファイルのロックを解除するまで、キューに入れられます。これを強制的にsession_write_close()とすることができますが、進捗情報をセッションファイルと共有しようとしているので、これは役に立ちません。postスクリプトは、セッションデータを開いて書き込み可能に保つ必要があります。

あなたはpostprogressスクリプト間でデータを共有するための別の方法を考え出す必要があります - それは実行だ全体postがオープンセッションデータを持っている場合post後に実行が終了するまで、progressは、セッションデータにアクセスすることはできません。セッションIDを使用して、postに書き込みアクセス権を持つ一時ファイルを作成し、進捗インジケーター・データを入れることができます。 progressは、ファイルをチェックしてそのデータを返すことができます。 IPC(プロセス間通信)には多くのオプションがあります。これは特に美しいものではありませんが、最大の移植性という利点があります。

補足として、文字列をsetInterval()に渡さず、関数を渡してください。

var progress = setInterval(ask, 500); 

をしかし - ask() AJAX機能のsuccess/errorハンドラでsetTimeout()を使う方が良いでしょう。だからあなたの行は、実際に読んでください。これは、setInterval()を使用すると、前の状態に関係なく新しい要求が開始されるためです。前の要求が完了するまで待ってから次の要求を開始する方が効率的です。だから私はこれ以上のような何かをするでしょう:

<script type="text/javascript"> 

    // We'll set this to true when the initail POST request is complete, so we 
    // can easily know when to stop polling the server for progress updates 
    var postComplete = false; 

    var ask = function() { 

    var time = new Date().getTime(); 

    $.ajax({ 

     type: 'get', 
     url: '/url/to/progress' + '?time=' + time, 

     success: function(data) { 
     $("#progress").html(data); 
     if (!postComplete) 
      setTimeout(ask, 500); 
     } 
     }, 
     error: function() { 
     // We need an error handler as well, to ensure another attempt gets scheduled 
     if (!postComplete) 
      setTimeout(ask, 500); 
     } 
     } 

    }); 

    } 

    $("#test").click(function() { 

    // Since you only ever call post() once, you don't need a seperate function. 
    // You can just put all the post() code here. 

    var time = new Date().getTime(); 

    $.ajax({ 

     type: 'post', 
     url: '/url/to/post' + '?time=' + time, 
     data: { 
     "some": "data" 
     }, 

     success: function(data) { 
     postComplete = true; 
     alert(data); 
     } 
     error: function() { 
     postComplete = true; 
     } 

    }); 

    if (!postComplete) 
     setTimeout(ask, 500); 
    } 

    }); 

</script> 

...これはまだセッションの問題を解決しません。

+0

あなたはリグだった。関数session_write_close()が見つかりました。私がする必要があったのは、アクションの開始時にセッションを閉じて、セッション変数を更新するためだけにセッションを再開することでした。ありがとう、あなたのアドバイスに感謝します。 – pawelo

+0

同じスクリプトでセッションデータを複数回開閉することに注意してください - 人々はそれが確実に機能しないと不平を言うのを見たことがあるので、あなたが思いついたものを徹底的にテストするようにしてください。 – DaveRandom

+0

うーん、もっと良い解決策は、進捗変数をDbまたはファイルに格納することです。私はそれをチェックしなければならない、ありがとう! – pawelo

6

上記の@DaveRandomは、あなたがセッションストレージロックの被害者であると正しく指摘しています。

回避策は非常に簡単です。 post()を処理するスクリプトがセッションデータのロックを解除して、ask()を処理するスクリプトがこのセッションデータにアクセスできるようにしたいとします。 session_write_closeでそれを行うことができます。

あなたがそれに応じpostのためのスクリプトを構築する必要があるので、ここでは細かい活字は、session_write_closeを呼び出した後は、セッション変数にアクセスすることができないということです。

  1. あなたが$_SESSIONから必要と保存されますすべてのデータを読み込みそれのコピー。
  2. session_write_closeを呼び出してセッションロックを解除します。
  3. 長時間の操作を続けます。セッションデータが必要な場合は、$_SESSIONではなく、自分のコピーから直接取り出してください。

また、スクリプトの存続期間中にセッションで複数回のロックを切り替えることができますスクリプトそれは寝ている間、他のスクリプトはせずにセッションデータにアクセスできるように

session_start(); 
$_SESSION['name'] = 'Jon'; 

// Quick operation that requires session data 
echo 'Hello '.$_SESSION['name']; 

// Release session lock 
session_write_close(); 

// Long operation that does not require session data. 
sleep(10); 

// Need access to session again 
session_start(); 
echo 'Hello again '.$_SESSION['name']; 

この配置は、それを作ります問題。

+0

"私は質問を読み返すまで" post'スクリプトでsession_write_close()を使うだけで、セッションデータを使って長時間の操作の進捗状況を分かち合うことに気がつきました。明らかに、あなたはできません。進捗情報を更新する必要があるときに 'session_write_close()'とそれに続く 'session_start()'を試すことができます - これは自分自身で試みたことはありませんが、それがどこでも動作すれば、おそらくどこでも動作しません。したがって、「データを共有する別の方法を考え出す必要がある」 – DaveRandom

関連する問題