30

正如这里所建议的:https ://gist.github.com/HenrikJoreteg/2502497 ,我正在尝试将 onprogress 功能添加到我的jQuery.ajax()文件上传中。上传工作正常,并且 onprogress 事件正在触发,但不像我预期的那样 - 不是在某个时间间隔重复触发,而是在上传完成时只触发一次。有没有办法指定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!');
                }
            }
        }
    });

嗯,已经好几年了。我重新审视了这一点,并使用GetFree的答案,将我的代码更新为以下内容:

$('#file_input').change(function()
{
    var file = this.files[0];
    $('#upload_button').click(funtion(e)
    {
        req = new XMLHttpRequest();
        req.upload.addEventListener('progress', updateProgress, false);
        req.addEventListener('load', transferComplete, false);
        var url  = 'https://my.url'; 
        req.open('POST', url, true);
        req.setRequestHeader('Content-Type', myFileType);
        req.setRequestHeader('Content-Length', myFileLength);
        req.send(file);
    });
);
function updateProgress(e)
{
    var percent = Math.floor(e.loaded / e.total * 100);
    console.log("percent = " + percent);
}
function transferComplete(e)
{
    console.log("transfer complete");
}

我已将 GetFree 的帖子标记为已接受的答案。抱歉耽搁了。

4

3 回答 3

70

简短回答:
不,您不能使用xhrFields.

长答案:

XmlHttpRequest 对象中有两个进度事件:

  • 响应进度( 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 ;
    }
});

xhroption 参数必须是返回原生 XmlHttpRequest 对象以供 jQuery 使用的函数。

于 2014-01-08T00:00:47.583 回答
4

在发出请求之前,您需要将事件处理程序添加到请求本身。jQuery.ajax 允许通过“beforeSend”属性http://api.jquery.com/jQuery.ajax/

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

* 编辑 * 确保查看该示例链接的第二个代码示例。我相信第一个对于现代版本的 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
  }
});
于 2013-06-06T20:46:23.117 回答
1

这有点像 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
        }

简短的回答......是的。希望这可以帮助 :-)

于 2018-09-10T14:43:31.843 回答