Javascript 显示使用 XHR2/AJAX 下载文件的进度条

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39589917/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 22:43:02  来源:igfitidea点击:

Show a progress bar for downloading files using XHR2/AJAX

javascriptjqueryajaxxmlhttprequest

提问by Ayan

I am trying to download files using Ajax and show a custom download progress bar.

我正在尝试使用 Ajax 下载文件并显示自定义下载进度条。

The problem is I can't understand how to do so. I wrote the code to log the progress but don't know how to initiate the download.

问题是我不明白该怎么做。我写了代码来记录进度,但不知道如何启动下载。

NOTE:The files are of different types.

注意:这些文件是不同类型的。

Thanks in advance.

提前致谢。

JS

JS

// Downloading of files
filelist.on('click', '.download_link', function(e){
    e.preventDefault();
    var id = $(this).data('id');
    $(this).parent().addClass("download_start");

    $.ajax({
        xhr: function () {
            var xhr = new window.XMLHttpRequest();
            // Handle Download Progress
            xhr.addEventListener("progress", function (evt) {
                if(evt.lengthComputable) {
                    var percentComplete = evt.loaded / evt.total;
                    console.log(percentComplete);
                }
            }, false);
            return xhr;
        },
        complete: function () {
            console.log("Request finished");
        }
    })
});

HTML and PHP

HTML 和 PHP

    <li>
    <div class="f_icon"><img src="' . $ico_path . '"></div>
    <div class="left_wing">
       <div class="progressbar"></div>
       <a class="download_link" href="#" id="'.$file_id.'"><div class="f_name">' . $full_file_name . '</div></a>
       <div class="f_time_size">' . date("M d, Y", $file_upload_time) . '&nbsp; &#149; &nbsp;' . human_filesize($file_size) . '</div>
    </div>

    <div class="right_wing">
       <div class="f_delete">
       <a class="btn btn-danger" href="#" aria-label="Delete" data-id="'.$file_id.'" data-filename="'.$full_file_name.'"><i class="fa fa-trash-o fa-lg" aria-hidden="true" title="Delete this?"></i>
       </a>
    </div>
   </div>
    </li>

回答by Dekel

If you want to show the user a progress-bar of the downloading process - you must do the download within the xmlhttprequest. One of the problems here is that if your files are big - they will be saved in the memoryof the browser before the browser will write them to the disk (when using the regular download files are being saved directly to the disk, which saves a lot of memory on big files).

如果您想向用户显示下载过程的进度条 - 您必须在 xmlhttprequest 中进行下载。这里的问题之一是,如果您的文件很大 - 它们将在浏览器将它们写入磁盘之前保存浏览器的内存中(使用常规下载文件时直接保存到磁盘,这样可以节省大文件上的大量内存)。

Another important thing to note - in order for the lengthComputableto be true - your server must send the Content-Lengthheader with the size of the file.

另一件需要注意的重要事情 - 为了lengthComputable使 成为真的 - 您的服务器必须发送Content-Length带有文件大小的标头。

Here is the javascript code:

这是javascript代码:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="a1" data-filename="filename.xml">Click to download</div>
<script>
$('#a1').click(function() {
    var that = this;
    var page_url = 'download.php';

    var req = new XMLHttpRequest();
    req.open("POST", page_url, true);
    req.addEventListener("progress", function (evt) {
        if(evt.lengthComputable) {
            var percentComplete = evt.loaded / evt.total;
            console.log(percentComplete);
        }
    }, false);

    req.responseType = "blob";
    req.onreadystatechange = function () {
        if (req.readyState === 4 && req.status === 200) {
            var filename = $(that).data('filename');
            if (typeof window.chrome !== 'undefined') {
                // Chrome version
                var link = document.createElement('a');
                link.href = window.URL.createObjectURL(req.response);
                link.download = filename;
                link.click();
            } else if (typeof window.navigator.msSaveBlob !== 'undefined') {
                // IE version
                var blob = new Blob([req.response], { type: 'application/force-download' });
                window.navigator.msSaveBlob(blob, filename);
            } else {
                // Firefox version
                var file = new File([req.response], filename, { type: 'application/force-download' });
                window.open(URL.createObjectURL(file));
            }
        }
    };
    req.send();
});
</script>

And here is an example for the php code you can use:

这是您可以使用的 php 代码示例:

<?php
$filename = "some-big-file";
$filesize = filesize($filename);

header("Content-Transfer-Encoding: Binary");
header("Content-Length:". $filesize);
header("Content-Disposition: attachment");

$handle = fopen($filename, "rb");
if (FALSE === $handle) {
    exit("Failed to open stream to URL");
}

while (!feof($handle)) {
    echo fread($handle, 1024*1024*10);
    sleep(3);
}

fclose($handle);

Note that I added a sleep to simulate a slow connection for testing on localhost.
You should remove thison production :)

请注意,我添加了一个 sleep 来模拟慢速连接以在 localhost 上进行测试。
你应该在生产中删除它:)