web-dev-qa-db-ja.com

XMLHttpRequestから進捗を取得する方法

XMLHttpRequestの進行状況(アップロードされたバイト数、ダウンロードされたバイト数)を取得することはできますか?

これは、ユーザーが大きなファイルをアップロードしているときにプログレスバーを表示するのに役立ちます。標準APIはそれをサポートしていないようですが、そこにあるブラウザのいずれかに非標準の拡張機能があるのでしょうか?クライアントはアップロード/ダウンロードされたバイト数を知っているので、結局、持っているのはかなり明白な機能のようです。

注:「進行状況を確認するためにサーバーをポーリングする」という代替手段を認識しています(現在これを実行しています)。これに関する主な問題(複雑なサーバー側コードを除く)は、ほとんどのISPが不十分なアップストリームを提供するため、通常、大きなファイルをアップロードしている間、ユーザーの接続が完全に制限されることです。したがって、追加のリクエストを行うことは、私が期待したほど反応がよくありません。ブラウザが常に持っているこの情報を取得する方法(非標準かもしれません)があることを望んでいました。

130
Pete

アップロードされたバイトについては、非常に簡単です。 xhr.upload.onprogressイベントを監視するだけです。ブラウザは、アップロードするファイルのサイズとアップロードされたデータのサイズを認識しているため、進捗情報を提供できます。

ダウンロードされたバイト(xhr.responseTextで情報を取得する場合)については、サーバーリクエストで送信されるバイト数がブラウザにわからないため、少し難しくなります。この場合、ブラウザが知っているのは、受信するバイトのサイズだけです。

これには解決策があります。ブラウザが受信するバイトの合計サイズを取得するには、サーバースクリプトにContent-Lengthヘッダーを設定するだけで十分です。

詳細については、 https://developer.mozilla.org/en/Using_XMLHttpRequest にアクセスしてください。

例:私のサーバースクリプトはZipファイルを読み取ります(5秒かかります):

$filesize=filesize('test.Zip');

header("Content-Length: " . $filesize); // set header length
// if the headers is not set then the evt.loaded will be 0
readfile('test.Zip');
exit 0;

サーバースクリプトのダウンロードプロセスを監視できるようになりました。全体の長さを知っているからです。

function updateProgress(evt) 
{
   if (evt.lengthComputable) 
   {  // evt.loaded the bytes the browser received
      // evt.total the total bytes set by the header
      // jQuery UI progress bar to show the progress on screen
     var percentComplete = (evt.loaded / evt.total) * 100;  
     $('#progressbar').progressbar( "option", "value", percentComplete );
   } 
}   
function sendreq(evt) 
{  
    var req = new XMLHttpRequest(); 
    $('#progressbar').progressbar();    
    req.onprogress = updateProgress;
    req.open('GET', 'test.php', true);  
    req.onreadystatechange = function (aEvt) {  
        if (req.readyState == 4) 
        {  
             //run any callback here
        }  
    };  
    req.send(); 
}
134
albanx

Firefoxは XHRダウンロード進行状況イベント をサポートします。

9

AJAXパターンの進行状況インジケーターについては、こちらで説明しています。

http://ajaxpatterns.org/Progress_Indicator

最も有望なアプローチの1つは、サーバーへの2番目の通信チャネルを開いて、どの程度の転送が完了したかを確認することです。

8
Sean McMains
7

アップロードされた合計については、それを処理する方法はないようですが、ダウンロードしたいものに似たものがあります。 readyStateが3になったら、responseTextを定期的にクエリして、ダウンロードされたすべてのコンテンツをStringとして取得できます(IEでは機能しません)。任意の時点でダウンロードされるバイト数は、responseTextに格納されている文字列の合計バイト数に等しくなります。

アップロードの質問に対するオールオアナッシングアプローチの場合、アップロード用の文字列を渡す必要があるため(そして、その合計バイト数を決定することができます)、readyState 0および1に送信される合計バイトは0になり、readyStateの合計は2は、渡された文字列の合計バイト数になります。readyState3と4で送受信される合計バイト数は、元の文字列のバイト数とresponseTextの合計バイト数の合計になります。

5
Orclev
<!DOCTYPE html>
<html>
<body>
<p id="demo">result</p>
<button type="button" onclick="get_post_ajax();">Change Content</button>
<script type="text/javascript">
        function update_progress(e)
        {
          if (e.lengthComputable)
          {
            var percentage = Math.round((e.loaded/e.total)*100);
            console.log("percent " + percentage + '%' );
          }
          else 
          {
                console.log("Unable to compute progress information since the total size is unknown");
          }
        }
        function transfer_complete(e){console.log("The transfer is complete.");}
        function transfer_failed(e){console.log("An error occurred while transferring the file.");}
        function transfer_canceled(e){console.log("The transfer has been canceled by the user.");}
        function get_post_ajax()
        {
                var xhttp;
                if (window.XMLHttpRequest){xhttp = new XMLHttpRequest();}//code for modern browsers} 
                else{xhttp = new ActiveXObject("Microsoft.XMLHTTP");}// code for IE6, IE5               
                xhttp.onprogress = update_progress;
                xhttp.addEventListener("load", transfer_complete, false);
                xhttp.addEventListener("error", transfer_failed, false);
                xhttp.addEventListener("abort", transfer_canceled, false);              
                xhttp.onreadystatechange = function()
                {
                if (xhttp.readyState == 4 && xhttp.status == 200)
                {
                        document.getElementById("demo").innerHTML = xhttp.responseText;
                }
                };
          xhttp.open("GET", "http://it-tu.com/ajax_test.php", true);
          xhttp.send();
        }
</script>
</body>
</html>

Result

3
Forums Lover

Apacheインストールへのアクセス権があり、サードパーティのコードを信頼している場合、 Apache upload progress module を使用できます(Apacheを使用している場合、 nginx upload progress module もあります)。

それ以外の場合は、帯域外でヒットしてファイルのステータスを要求できるスクリプトを作成する必要があります(たとえば、tmpファイルのファイルサイズを確認します)。

Firefox 3で進行中の作業がいくつかありますが、ブラウザにアップロードの進行状況のサポートを追加すると思いますが、それはすべてのブラウザに取り込まれ、しばらくの間広く採用されることはありません(残念です)。

2
Aeon