web-dev-qa-db-ja.com

xhrFieldsを使用して、進行中の機能をjQuery.ajax()に追加できますか?

ここで提案されているように、 https://Gist.github.com/HenrikJoreteg/2502497jQuery.ajax()ファイルアップロードに進行中の機能を追加しようとしています。アップロードは正常に機能し、onprogressイベントが発生しますが、期待どおりではありません。ある時間間隔で繰り返し発生するのではなく、アップロードが完了したときに一度だけ発生します。進行中の更新の頻度を指定する方法はありますか?または、できないことをしようとしていますか?ここに私のコードがあります:

$.ajax(
{
    async: true,
    contentType: file.type,
    data: file,
    dataType: 'xml',
    processData: false,
    success: function(xml)
    {
        // Do stuff with the returned xml
    },
    type: 'post',
    url: '/fileuploader/' + file.name,
    xhrFields:
    {
        onprogress: function(progress)
        {
            var percentage = Math.floor((progress.total / progress.totalSize) * 100);
            console.log('progress', percentage);
            if (percentage === 100)
            {
                console.log('DONE!');
            }
        }
    }
});
25
dcorsello

短い答え:
いいえ、あなたはxhrFieldsを使ってやりたいことをすることはできません。

長答:

XmlHttpRequestオブジェクトには2つの進捗イベントがあります。

  • 応答の進行状況XmlHttpRequest.onprogress
    これは、ブラウザがサーバーからデータをダウンロードしているときです。

  • リクエストの進行状況XmlHttpRequest.upload.onprogress
    これは、ブラウザーがサーバーにデータを送信するときです(POSTパラメーター、Cookie、およびファイルを含む)

コードでは応答進行イベントを使用していますが、必要なのは要求進行イベントです。これがあなたのやり方です:

$.ajax({
    async: true,
    contentType: file.type,
    data: file,
    dataType: 'xml',
    processData: false,
    success: function(xml){
        // Do stuff with the returned xml
    },
    type: 'post',
    url: '/fileuploader/' + file.name,
    xhr: function(){
        // get the native XmlHttpRequest object
        var xhr = $.ajaxSettings.xhr() ;
        // set the onprogress event handler
        xhr.upload.onprogress = function(evt){ console.log('progress', evt.loaded/evt.total*100) } ;
        // set the onload event handler
        xhr.upload.onload = function(){ console.log('DONE!') } ;
        // return the customized object
        return xhr ;
    }
});

xhrオプションパラメータは、jQueryが使用するネイティブXmlHttpRequestオブジェクトを返す関数でなければなりません。

65
GetFree

送信する前に、イベントハンドラーをリクエスト自体に追加する必要があります。 jQuery.ajaxでは、これを「beforeSend」プロパティで許可しています http://api.jquery.com/jQuery.ajax/

例: http://www.dave-bond.com/blog/2010/01/JQuery-ajax-progress-HMTL5/

*編集*そのリンク例の2番目のコードサンプルを確認してください。最初のものはjQueryの最新バージョンでは時代遅れだと思います。

$.ajax({
  xhr: function()
  {
    var xhr = new window.XMLHttpRequest();
    //Upload progress
    xhr.upload.addEventListener("progress", function(evt){
      if (evt.lengthComputable) {
        var percentComplete = evt.loaded / evt.total;
        //Do something with upload progress
        console.log(percentComplete);
      }
    }, false);
    //Download progress
    xhr.addEventListener("progress", function(evt){
      if (evt.lengthComputable) {
        var percentComplete = evt.loaded / evt.total;
        //Do something with download progress
        console.log(percentComplete);
      }
    }, false);
    return xhr;
  },
  type: 'POST',
  url: "/",
  data: {},
  success: function(data){
    //Do something success-ish
  }
});
3
CooCooCaCha

これは、Stack Overflowの別の場所での別の答えのハックですが、あなたの質問には答えていると思います。サーバーからスクロール可能なdivに「ストリーム化された」データをポンピングする独自のニーズに合わせて修正しました(これにより、常に最後までスクロールし、時間の経過とともに進行し、レコードセット全体が完了するのを待たずに済みます) 。

クライアント側以下のコードは、結果のコンテンツをID「scrollable_area」(その後スクロール可能)で事前定義されたdivに追加します...

<div style="position:absolute; left:5px; right:5px; top:5px; height:35px;">
    <label for="auto_scroll">Auto Scroll</label> <input type="checkbox" id="auto_scroll" checked>
</div>
<div id="scrollable_area" style="position:absolute; overflow:auto; left:5px; right:5px; top:45px; bottom:5px;"></div>
<script type="text/javascript">
    var last_response_len = false;
    var auto_scroll = null;
    var scrollable_area = null;
    $().ready(function() {
        auto_scroll = document.getElementById("auto_scroll");
        scrollable_area = document.getElementById("scrollable_area");
        $.ajax("your_api_call.php", {
            xhrFields: {
                onprogress: function(e) {
                    var this_response, response = e.currentTarget.response;
                    if(last_response_len === false) {
                        this_response = response;
                        last_response_len = response.length;
                    } else {
                        this_response = response.substring(last_response_len);
                        last_response_len = response.length;
                    }
                    scrollable_area.innerHTML += this_response;
                    if(auto_scroll.checked) {
                        scrollable_area.scrollTop = scrollable_area.clientHeight + scrollable_area.scrollHeight + 500;
                    }
                }
            }
        })
        .done(function(data) {
            console.log("Completed response");
        })
        .fail(function(data) {
            console.log("Error: ", data);
        });
        console.log("your_api_call.php Request Sent!");
    });
</script>

サーバー側 "your_api_call.php"ファイル呼び出しは、出力を(データ行ごとに)フラッシュする必要があり、その後、上記の "scrollable_area" div内にすぐに表示できます。 ..

// Do Db loop
        while ($record = $recordset->fetch(PDO::FETCH_ASSOC)) {
            set_time_limit(10); // Don't timeout on large data sets seeing as this is a big task that we are wanting to watch progress!
            echo 'Do what you gotta do... ' . $record["register_id"] . '<br>';
            flush(); // Push to the client / ajax
            ob_flush(); // As above
        }

短い答え...はい。お役に立てれば :-)

1
Andrew Foster