使用Fetch API+Blob API下载文件的内存使用情况



我使用以下方法下载了大量文件,我担心它的内存使用情况。

Chrome的Blob存储系统设计文档提到了以下内容。

如果blob的内存空间已满,或者新blob太大而无法放入内存,则blob系统将使用该磁盘。这可以是将旧blob分页到磁盘,也可以将新的过大blob直接保存到磁盘。

然而,即使在多次浏览文档后,我仍然有以下问题:

  1. 我仍然不确定fetch的使用会在哪里影响这种行为,并首先将数据加载到内存中
  2. 如果fetch事实上改变了这种行为,是否建议使用此方法限制文件大小(超过该大小的任何文件都不应该下载(
  3. 在其他(非铬浏览器(中会有什么行为
const download = downloadLinks => {
const _download = async ( downloadLink ) => {
const blobURL = await fetch(downloadLink, {  
responseType: 'blob'  
})
.then(res => res.blob())
.then(blob => window.URL.createObjectURL(blob))

const fileName = downloadLink.substr(downloadLink.lastIndexOf('/'))

const a = document.createElement('a')  
a.href = blobURL
a.setAttribute('download', fileName)  
document.body.appendChild(a)  
a.click()
a.remove()  

window.URL.revokeObjectURL(blobURL)
}
const downloadInterval = () => {
if (downloadLinks.length == 0) return
const url = downloadLinks.pop()

_download(url)

if (downloadLinks.length !== 0) setTimeout(downloadInterval, 500)
}
setTimeout(downloadInterval, 0)
}

以下是我浏览过的一些资源。这些回答了这三个问题的一部分,但我有点太担心如果Blob第一次加载到内存中或没有加载,fetch可能会产生什么影响。

  • https://chromium.googlesource.com/chromium/src/+/HEAD/存储/浏览器/bob/LEADME.md

  • https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Browser_storage_limits_and_eviction_criteria

  • JavaScript最大Blob大小有任何限制吗

  • https://github.com/eligrey/FileSaver.js/#supported-浏览器

简短的回答是肯定的!

Fetch实际上改变了这种行为,因为它首先将数据加载为加载到内存中的ReadableStream。因此,请改用以下代码。
  • 此方法可以下载的最大文件大小取决于磁盘大小、操作系统和浏览器。并没有一个适用于所有系统的确切数字。这里已经详细回答了这个问题。

  • "没有明显的硬性限制。我能够创建明显大于";800MiB";FileSaver.js声称。它不使用磁盘空间来支持更大的Blob,所以它都在内存中,可能是操作系统将内存分页到磁盘。这意味着可能会出现比内存大的Blob,尽管性能可能不好">

    请点击2号和此处的链接了解更多详细信息。

  • 正如@kaiido在评论中提到的,以及我通过运行一些测试发现的一些东西,如果你想要一个大文件,以及如何利用Blob架构(如果可能的话,可以直接在磁盘中加载文件(,上面的代码可以修改如下。

    const download = downloadLinks => {
    const _download = url => {
    const xhr = new XMLHttpClient()
    xhr.responseType = 'blob'
    xhr.open('GET', url)
    xhr.onload = () => {
    const fileName = url.substr(url.lastIndexOf('/'))
    const blobURL = window.URL.createObjectURL(xhr.response)
    const a = document.createElement('a')  
    a.href = blobURL
    a.setAttribute('download', fileName)  
    document.body.appendChild(a)  
    a.click()
    a.remove()  
    window.URL.revokeObjectURL(blobURL)
    }
    xhr.send(null)
    }
    const downloadInterval = () => {
    if (downloadLinks.length == 0) return
    const url = downloadLinks.pop()
    
    _download(url)
    
    if (downloadLinks.length !== 0) setTimeout(downloadInterval, 500)
    }
    setTimeout(downloadInterval, 0)
    }
    

    这里的差异是由线CCD_ 2造成的。尽管在最初的问题中可以看到,我们的请求对象有一个responseType选项,但它不起作用,因为fetch API最初没有这个选项。

    最新更新