JQuery ajaxリクエストの進捗状況を取得する最もクリーンな方法は何ですか?


104

単純なJavaScriptでは非常に簡単です:コールバックを添付するだけです {XMLHTTPRequest}.onprogress

var xhr = new XMLHttpRequest();

xhr.onprogress = function(e){
    if (e.lengthComputable)
        var percent = (e.loaded / e.total) * 100;
};

xhr.open('GET', 'http://www...', true);
xhr.onreadystatechange = function() {
    ...
};
xhr.send(null);

しかし、私はJQuery($.get()または$.ajax())でhtmlデータをダウンロードするajaxサイトをやっていて、小さなプログレスバーで表示するためにリクエストの進捗状況を取得するための最良の方法であると思いましたが、不思議なことに、私はそうではありませんJQueryドキュメントで有用なものを見つけています...



1
おお、ありがとう!そのオーバーライドXHRする必要が..奇妙なことは、私はクローム開発ツールで、いわゆる検査をしたことであるjqXHRオブジェクト(によって返さXHRオブジェクトのラッパーを$.ajax())、見つかったprogress(と一緒にして属性をabortcompletesuccess、など)が、 JQueryドキュメントではこれが欠落しています:api.jquery.com/jQuery.ajax/#jqXHR
guari

3
github.com/englercj/jquery-ajax-progress私はこれを使用していますが、他の回答とまったく同じですが、より一般的なものを使用したいと思います
KeizerBridge 2014年

回答:


139

次のようなもの$.ajax(HTML5のみ):

$.ajax({
    xhr: function() {
        var xhr = new window.XMLHttpRequest();
        xhr.upload.addEventListener("progress", function(evt) {
            if (evt.lengthComputable) {
                var percentComplete = evt.loaded / evt.total;
                //Do something with upload progress here
            }
       }, false);

       xhr.addEventListener("progress", function(evt) {
           if (evt.lengthComputable) {
               var percentComplete = evt.loaded / evt.total;
               //Do something with download progress
           }
       }, false);

       return xhr;
    },
    type: 'POST',
    url: "/",
    data: {},
    success: function(data){
        //Do something on success
    }
});

1
有望に見えますが、これはどのように機能するのでしょうか?パイプライン全体は3つのステップで構成されます-リクエストを送信し、バックエンドでリクエストを処理してデータを生成し、それを返します。クライアント側では、バックエンドで何が行われているのか、進行状況を計算するのにどのくらいの時間がかかるのかをどのようにして知ることができますか?
SexyBeast 2017

1
HTTP応答ヘッダーは、予想されるバイト数を示します。この進捗状況は、これまでに受信されたバイト数を単にカウントしています。HTTP応答が実際に送信されるまでゼロのままです
J. Allen

2
それはPOSTでのみ機能し、GETや他のものも持っていませんか?
Raz

43

jQueryはすでにpromiseを実装しているため、このテクノロジーを使用し、イベントロジックをoptionsパラメーターに移動しない方が良いでしょう。プログレスプロミスを追加するjQueryプラグインを作成しました。これで、他のプロミスと同様に簡単に使用できます。

$.ajax(url)
  .progress(function(){
    /* do some actions */
  })
  .progressUpload(function(){
    /* do something on uploading */
  });

githubで確認してください


IFIファクトリーの使い方が気に入りました。私はそのテクニックを知りませんでした!
CodeArtist 2015年

これは現在、ここで提案されている最良のソリューションです。
アトムレス、2015年

2
機能的で洗練されたソリューションですが、非推奨の.successおよび.errorへのすべての呼び出しが壊れるため、既存のコードが壊れる可能性があることに気づくかもしれません。また、jqXHRオブジェクトに設定したすべての非標準属性を削除します。jqXHRのすべての標準プロミスに対して行われるため、uploadProgressコールバックの「this」へのコンテキストも提供しません(進行状況については同じかもしれませんが、テストされていません)。したがって、コンテキストをクロージャーで渡す必要があります。
率直

4
エラーが表示されます:TypeError: $.ajax(...).progress(...).progressUpload is not a function....問題は何ですか?
ユニバーサルグラスプ

@UniversalGraspこんにちは、githubで問題を開いて、行ったことに関する情報を提供してください。このライブラリは古くから更新されていません:) jQuery自体で何かが変更された可能性があります
likerRr

5

私は、Ajaxオブジェクトの構成をインターセプトする3つの異なる方法を試しました。

  1. 私の最初の試みはを使用しましたがxhrFields、これは1つのリスナーしか許可せず、ダウンロード(アップロードではなく)の進行状況にのみアタッチし、不要なコピーアンドペーストのように見えるものを必要とします。
  2. 2回目の試行でprogressは、返されたpromiseに関数をアタッチしましたが、独自のハンドラーの配列を維持する必要がありました。XHRにアクセスする場所とjQuery XHRにアクセスする場所があるため、ハンドラーをアタッチするのに適したオブジェクトを見つけることができませんでしたが、遅延オブジェクト(その約束のみ)にはアクセスできませんでした。
  3. 3回目の試行では、ハンドラーをアタッチするためのXHRに直接アクセスできましたが、やはり多くのコピーアンドペーストコードが必要でした。
  4. 3回目の試行をまとめ、jQuery ajaxを自分のものに置き換えました。唯一の潜在的な欠点は、自分のxhr()設定を使用できなくなることです。がoptions.xhr関数であるかどうかを確認することで、それを可能にすることができます。

実際にpromise.progress関数を呼び出すxhrProgressので、後で簡単に見つけることができます。アップロードリスナーとダウンロードリスナーを区別するために、別の名前を付けることができます。元のポスターがすでに必要なものを手に入れたとしても、これが誰かを助けることを願っています。

(function extend_jQuery_ajax_with_progress( window, jQuery, undefined )
{
var $originalAjax = jQuery.ajax;
jQuery.ajax = function( url, options )
{
    if( typeof( url ) === 'object' )
    {options = url;url = undefined;}
    options = options || {};

    // Instantiate our own.
    var xmlHttpReq = $.ajaxSettings.xhr();
    // Make it use our own.
    options.xhr = function()
    {return( xmlHttpReq );};

    var $newDeferred = $.Deferred();
    var $oldPromise = $originalAjax( url, options )
    .done( function done_wrapper( response, text_status, jqXHR )
    {return( $newDeferred.resolveWith( this, arguments ));})
    .fail( function fail_wrapper( jqXHR, text_status, error )
    {return( $newDeferred.rejectWith( this, arguments ));})
    .progress( function progress_wrapper()
    {
        window.console.warn( "Whoa, jQuery started actually using deferred progress to report Ajax progress!" );
        return( $newDeferred.notifyWith( this, arguments ));
    });

    var $newPromise = $newDeferred.promise();
    // Extend our own.
    $newPromise.progress = function( handler )
    {
        xmlHttpReq.addEventListener( 'progress', function download_progress( evt )
        {
            //window.console.debug( "download_progress", evt );
            handler.apply( this, [evt]);
        }, false );
        xmlHttpReq.upload.addEventListener( 'progress', function upload_progress( evt )
        {
            //window.console.debug( "upload_progress", evt );
            handler.apply( this, [evt]);
        }, false );
        return( this );
    };
    return( $newPromise );
};
})( window, jQuery );

だから私はあなたのソリューションを実装しようとしましたが、このコードは私には理解するには少しプロすぎる-これをどのように使用するのですか?私は私のdocument.readyの前にあなたのコード全体をコピーして貼り付けてみました$.ajax({ ... }).progress(function(evl) { console.log(evl); });が、何も起こりません。手伝って頂けますか?:)
Patrick DaVader

どのバージョンのjQueryを使用していますか?
Flo Schild、2015年

@FloSchild、あなた自身のフォーマット設定のためだけに私のコードを編集しないでください。
MarkMYoung

3

jQueryには、すべてのajax呼び出しAjaxSetup()などのグローバルajaxハンドラーを登録しbeforeSendたりcompletexhrオブジェクトにアクセスして目的の進行状況を実行したりできる関数があります


2
リンクをありがとう。答えに例を含めることができますか?
Michael Scheper、2015年

$ .ajaxSetup({xhr:function(){console.log( 'setup XHR ...');}});
Flo Schild、2015年

7
そして、質問に答える例は?特にリンクされたページが進捗状況について何も述べていない場合、私は多くのいじくりと読んでいる答えに賛成投票できないと思います。グローバルコールバック関数は、それぞれのグローバルAjaxのイベントハンドラmethods-で設定する必要があります。正直なところ、私は特に「注意言い、そのページ上の警告、与えられた、この懐疑的だ.ajaxStart().ajaxStop().ajaxComplete().ajaxError().ajaxSuccess().ajaxSend()-ratherのオプションオブジェクト内より$.ajaxSetup()」< api.jquery.com/jQuery.ajaxSetup/#entry-longdesc >
Michael Scheper

1
ドキュメントから今後のAjaxリクエストのデフォルト値を設定します。その使用は推奨されません。
Oyvind

-1

http://www.htmlgoodies.com/beyond/php/show-progress-report-for-long-running-php-scripts.html

私は同様の解決策を探していましたが、これは十分に活用されています。

var es;

function startTask() {
    es = new EventSource('yourphpfile.php');

//a message is received
es.addEventListener('message', function(e) {
    var result = JSON.parse( e.data );

    console.log(result.message);       

    if(e.lastEventId == 'CLOSE') {
        console.log('closed');
        es.close();
        var pBar = document.getElementById('progressor');
        pBar.value = pBar.max; //max out the progress bar
    }
    else {

        console.log(response); //your progress bar action
    }
});

es.addEventListener('error', function(e) {
    console.log('error');
    es.close();
});

}

そしてあなたのサーバー出力

header('Content-Type: text/event-stream');
// recommended to prevent caching of event data.
header('Cache-Control: no-cache'); 

function send_message($id, $message, $progress) {
    $d = array('message' => $message , 'progress' => $progress); //prepare json

    echo "id: $id" . PHP_EOL;
    echo "data: " . json_encode($d) . PHP_EOL;
    echo PHP_EOL;

   ob_flush();
   flush();
}


//LONG RUNNING TASK
 for($i = 1; $i <= 10; $i++) {
    send_message($i, 'on iteration ' . $i . ' of 10' , $i*10); 

    sleep(1);
 }

send_message('CLOSE', 'Process complete');

これは、AJAX呼び出しではなく、実行中のPHPスクリプトの進行状況を示します。
Sinus Mackowaty

-3

手順に従ってAjaxリクエストの進行状況を表示します。

  1. HTMLとCSSを使用してスピナーを作成するか、ブートストラップスピナーを使用します。
  2. エンドユーザーが無限ループまたはしきい値制限時間のAJAXデータを要求しているときに、スピナーを表示します。
  3. したがって、AJAXリクエストの成功/エラー結果の後に、現在表示されているスピナーを削除して、結果を表示します。

簡単にするために、この目的でスピナーを動的に表示および非表示にするためにJSクラスを使用することをお勧めします。

これが役に立てば幸いです!


2
それは「進行中」ではなく、「待機中」のアニメーションを表示するだけです。
Sinus Mackowaty
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.