web-dev-qa-db-ja.com

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

単純な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のドキュメントで有用なものを見つけていません...

90
guari

$.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
    }
});
130
mattytommo

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

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

github で確認してください

37
likerRr

jQueryには AjaxSetup() 関数があり、beforeSendcompleteなどのグローバルajaxハンドラーをすべてのajax呼び出しに登録できるほか、xhrにアクセスできます。あなたが探している進歩をするオブジェクト

5
Kevin Pei

Ajaxオブジェクトの構築をインターセプトする3つの異なる方法について試しました。

  1. 私の最初の試みはxhrFieldsを使用しましたが、それは1人のリスナーのみを許可し、ダウンロードにのみ接続し(アップロードではなく)、不必要なコピーアンドペーストのように見えるものを必要とします。
  2. 2回目の試行では、返されたpromiseにprogress関数を添付しましたが、ハンドラーの独自の配列を維持する必要がありました。ある場所では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) {
            // Download progress
            xmlHttpReq.addEventListener('progress', function download_progress(evt) {
                // window.console.debug( "download_progress", evt );
                handler.apply(this, [evt]);
            }, false);

            // Upload progress
            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);
4
MarkMYoung