JavaScript 将 blob 保存到本地存储

11

我正在尝试将通过 AJAX 检索的 blob 数据(网站图标)保存到 localStorage 中。

代码:

var xhr = new XMLHttpRequest();
xhr.open('GET', 
'http://g.etfv.co/http://www.google.com',
true);
xhr.responseType = "blob";
xhr.onload = function(e){ //Stringify blob...
    localStorage['icon'] = JSON.stringify(xhr.response);
    //reload the icon from storage
    var fr = new FileReader();
    fr.onload = 
        function(e) {
            document.getElementById("myicon").src = fr.result;
        }
    fr.readAsDataURL(JSON.parse(localStorage['icon']));
    }
xhr.send(null);

这段代码是从这里改编而来的,在进行了一些小修改后,使其能够与localStorage一起使用。

localStorage将所有数据保存为字符串,因此需要在保存之前对blob进行字符串化

JSON不支持将blob作为其支持的类型之一,因此这段代码失败了也就不足为奇了。

有没有办法将blob存入localStorage中呢?


不确定,只是猜测,但如果您的请求响应本身就是二进制文件,则可以直接将其保存在localStorage中。 - DontVoteMeDown
啊,抱歉,我在想indexeddb,没事了。 - user229044
可能是https://dev59.com/Keo6XIcBkEYKwwoYOR0q的重复问题。 - makeitmorehuman
@XGreen 嘿,伙计!那不是一个问题,那是一篇博士论文。无论如何我会检查它的。 - MadeOfAir
2个回答

15

只需将blob作为数据URI存储在本地存储中

var xhr = new XMLHttpRequest();
xhr.open('GET', 
'http://g.etfv.co/http://www.google.com',
true);
xhr.responseType = "blob";
xhr.onload = function(e){ //Stringify blob...
    //reload the icon from storage
    var fr = new FileReader();
    fr.onload = 
        function(e) {
            localStorage['icon'] = e.target.result;
            document.getElementById("myicon").src = localStorage['icon'];
        }
    fr.readAsDataURL(xhr.response);
}
xhr.send(null);

好吧,至少这种方式效率低下。尝试将xhr.response.size()e.target.result.length进行比较。但最后我可能会退而求其次。 - MadeOfAir
3
它只是比原来大了33%(使用Base64编码),但这是我所知道的将blob转换为可用字符串的唯一方法。也许如果你找到更好的方法,你可以将它发布作为一个答案。 - Musa
如果我要存储网站图标,它们会很多,加上其他数据,所以所有网站图标可能会占用可用的5mb中的1mb。 - MadeOfAir
你可以使用以下链接进行压缩:https://pieroxy.net/blog/pages/lz-string/index.html - Dan Froberg
假设原始的favicon是PNG文件,它不会再被压缩。 - undefined

0
我们现在可以使用现代的fetch API来完成这项工作。

const getFromCacheOrDownload = async (url) => {
    const base64CachedImg = localStorage.getItem(url)
    if (base64CachedImg) {
        const response = await fetch(base64CachedImg)
        const blob = await response.blob()
        return URL.createObjectURL(blob)
    } else {
        const response = await fetch(url)
        if (response.status === 429) {
            console.log('too many requests')
        }
        const blob = await response.blob()
        const imageUrl = URL.createObjectURL(blob)
        const base64String = (await convertBlobToBase64(blob))
        localStorage.setItem(url, base64String)
        return imageUrl
    }
}

以上代码将尝试从缓存中获取图片。如果没有,它会下载并存储在缓存中。

在这个阶段,我们可能同样可以使用缓存存储而不是本地存储... - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接