【问题标题】:Can onprogress functionality be added to jQuery.ajax() by using xhrFields?可以使用 xhrFields 将 onprogress 功能添加到 jQuery.ajax() 吗?
【发布时间】:2013-03-18 02:15:37
【问题描述】:

正如这里的建议: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 的帖子标记为已接受的答案。抱歉耽搁了。

【问题讨论】:

  • 我正在尝试使用与您相同的 javascript 文件?在服务器端,我使用的是 PHP。你能给出一些服务器端代码示例,如何解析文件?这对我有很大帮助。 $_POST['file'] 不适合我。

标签: jquery ajax xmlhttprequest progress


【解决方案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
        }

简短回答...是的。希望这会有所帮助:-)

【讨论】:

    【解决方案2】:

    简答:
    不,你不能用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 ;
        }
    });
    

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

    【讨论】:

    • 如果无法使用xhrFields,那么在Chrome (v34.0) 中传递给onprogressthis object 是什么?
    • @c24w,我不明白你的意思。这里的问题是使用xhrFields可以配置响应进度,但不能配置请求进度。对于后者,您必须以不同的方式进行。
    • 我想我误解了,所以感谢澄清。所以xhr.addEventListener('progress', cb)(在xhr工厂函数中)等价于xhr.xhrFields.onprogress(cb)?
    • 两个事件处理程序(请求进度和响应进度)可以通过两种不同的方式设置。 XHR.onprogress = handler_functionXHR.addEventListener('progress',handler_function)。与另一个相同的事情。是XHR.upload.onprogress = handler_functionXHR.upload.addEventListener('progress',handler_function)
    【解决方案3】:

    您需要在请求发出之前将事件处理程序添加到请求本身。 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
      }
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-25
      • 1970-01-01
      • 2012-07-08
      • 2019-04-05
      • 2015-06-10
      • 1970-01-01
      • 2018-03-24
      相关资源
      最近更新 更多