突破本地离线存储5M限制的JS库localforage简介

这篇文章发布于 2018年06月4日,星期一,01:25,归类于 JS实例。 阅读 52356 次, 今日 5 次 18 条评论

 

更新于2021-03-09

如果项目无需兼容IE浏览器,可以试试使用yux-storage,一样的API,但是代码量少了一个数量级,就100行左右。

https://github.com/yued-fe/yux-storage

一、localforage项目简介

localforage项目地址:https://github.com/localForage/localForage

截止今日(2018-06-03),已经有12000+个星星,万级别的项目。

localforage项目star数据

JS文件下载(右键,另存为):localforage.min.js

localforage用来本地存储数据的。

说到本地存储数据,我们首先想到的是localStorage,应该很多小伙伴都用过,使用很简单。然而,localStorage却有下面一些缺点:

  1. 存储容量限制,大部分浏览器应该最多5M。我就遇到过localStorage存储字符然后尺寸爆掉的情况。
  2. 仅支持字符串,如果是存对象还需要将使用JSON.stringify和JSON.parse方法互相转换,有些啰嗦。
  3. 读取都是同步的。大多数情况下,还挺好使的。但,如果存储数据比较大,例如一张重要图片base64格式存储了,再读可能会有可感知的延迟时间。

localforage的作用就是用来规避上面localStorage的缺点,同时保留localStorage的优点而设计的。从命名上就可以看出两者关系不浅。

localStorage的优点是API非常简单,使用很方便。于是,localforagelocalStorage一模一样。

至于localStorage的不足,localforage和使用了其他HTML5 API进行规避,什么API呢?是IndexedDBWebSQL

也就是说,localforage的逻辑是这样的:优先使用IndexedDB存储数据,如果浏览器不支持,使用WebSQL,浏览器再不支持,使用localStorage

然后API还是localStorage的API,也就是数据增删改查通过getsetremoveclearlength等API。

二、localforage使用案例一则

您可以狠狠地点击这里:localforage存储blob格式的本地上传图片demo

第一次进入这个demo页面,只有一个上传图片按钮。

选择上传图片按钮,则会以blob的形式直接把选择的图片在网页中显示处理,例如:

上传图片示意

此时,你再刷新页面,则显示的还是这张图片,因为使用localforage把这张图片以blob数据形式存储在了本地。

刷新后的效果截图

相关HTML代码为:

<label for="fileImg">上传图片</label>
<input type="file" id="fileImg" accept="image/*" hidden> 
<p id="result"></p>

然后JS代码如下:

<script src="./localforage.min.js"></script>
<script>
var eleResult = document.getElementById('result');
// 图片资源
var eleImg = document.createElement('img');
// 获取本地存储数据
localforage.getItem('zxxImg', function (err, value) {
    if (err == null && value) {
        eleImg.src = value;
        eleResult.appendChild(eleImg);
    }
});
// 选择的本地文件以Blob形式呈现
var reader = new FileReader();
reader.onload = function(event) {
    if (!eleImg.src) {
        eleResult.appendChild(eleImg);
    }
    var blob = URL.createObjectURL(new Blob([event.target.result]));
    eleImg.src = blob;
    // blob本地存储
    localforage.setItem('zxxImg', blob);
};
// 选择的文件对象
var file = null;
document.getElementById('fileImg').addEventListener('change', function (event) {
    file = event.target.files[0];
    // 选择的文件是图片
    if (file.type.indexOf("image") == 0) {
        reader.readAsArrayBuffer(file);    
    }
});
</script>

可以看到,虽然localforage的API名称和localStorage一样,但是,在同步还是异步上却不同,localforage是异步执行的,用法示意如下。

localforage.getItem('key', function (err, value) {
    // 如果err不是null,则出错。否则value就是我们想要的值
});

更新于2019-08-04
补充一个自己常用的存取组合代码:

// 为了大家任意场景可以粘贴使用,全部改成字面量风格
var storage = {};
var storkey = 'SOME_KEY';
/**
 * 获取此时的本地存储
 */
var getStorage = function (callback) {
    callback = callback || function () {};
    // 获取
    localforage.getItem(storkey, function (err, value) {
        if (err == null && value) {
            storage = value;
        }
        callback(err);
    });
};
/**
 * 设置新的本地存储
 */
var setStorage = function (callback) {
    callback = callback || function () {};
    // 存储
    localforage.setItem(storkey, storage, function (err) {
        err && console.error(err);
        callback();
    });
};

通常使用先getStorage然后再初始化。

例如:

getStorage(function () {
    init();
});

三、localforage和indexDB的区别

indexDB为本地数据库存储,其功能非常强大,再复杂的结构存储都不在话下。localStorage只是使用了其功能中的一部分,很多功能受限,例如,localStorage一次只能存一个字段。

我之前有专门写过文章介绍HTML5 indexedDB,文章名为:“HTML5 indexedDB前端本地存储数据库实例教程”。

indexDB几乎空间无限,性能也不错,各种数据结构都支持,为何总感觉在业内不温不火呢?

我觉得很重要的原因之一就是上手成本,包括2方面:

  1. 前端需要了解数据库的一些基本概念,例如表,游标,事务,锁等。而业界普遍的前端都是与页面打交道的,数据库操作属于后端的后端了,离的有些远,于是,很多前端都不了解,需要从零开始的数据库学习。
  2. indexedDB的API又多又长又纷杂,学习成本高,容易记不住,网上好的资源少。

localforage的出现可谓曲线救国,通常我们的数据存储并不需要特别复杂,只要不是完完全全的离线开发,localforage足矣。既不浪费indexDB的好,又避开了indexDB高上手成本的坑。从这个角度看,indexDB应该要谢谢localforage

当然,如果存储的数据是负责的多行多列表结构,我建议还是老老实实花点功夫学习学习indexDB的使用。

四、结束语

indexDB IE10+浏览器支持。因此,如果想要使用localforage存储任意格式数据,需要注意下浏览器的兼容性问题,例如,本地图片存储Blob数据,IE9肯定是不支持的。这些浏览器怕是只能存字符串了。

一个东西是否有生命力,看的不是其是否强大,而是是否足够简单。

就酱紫,感谢阅读!

//zxx: 今天骑士、勇士第二场,骑士凶多吉少,我觉得第四节很可能会有垃圾时间。第一场着实可惜了。

(本篇完)

分享到:


发表评论(目前18 条评论)

  1. 控制台的indexDb一直loading中说道:

    项目中使用localforage,但遇到浏览器控制台中的IndexDb一直显示loading,导致无法读取数据和写入数据,请问有遇到类似问题么,怎么处理。部分代码
    const baseConfig = {
    // 暂时优先使用localstorage,indexDB一直处于Loading中BUG
    driver: [localforage.LOCALSTORAGE,localforage.INDEXEDDB, localforage.WEBSQL],
    name: “pro”,
    version: 1.0,
    storeName: “pro”, // 数据仓库的名称。在 IndexedDB 中为 dataStore,在 WebSQL 中为数据库 key/value 键值表的名称。仅含字母和数字和下划线。任何非字母和数字字符都将转换为下划线。
    size: 1073741824 // 现在只用于WebSQL
    };
    // 创建实例
    export const createLf = cfg => {
    const config = cfg || baseConfig;
    return localforage.createInstance(config);
    };

  2. 随便取的说道:

    请问怎么在vue中使用这个库啊?我直接用npm或者cnpm安装都不行,直接报错

  3. kerwin说道:

    好的,简单易用

  4. yunfeng说道:

    保存图片的Demo,不应该保存Blob的URL地址,这个地址生命周期和localforage是不一致的。当Blob释放掉的时候,Blob URL就读不到数据了。正确做法应该是缓存ArrayBuffer的二进制数据,然后取出cache的时候,再URL.createObjectURL

  5. LinQi说道:

    突然发现网页右上角张老师的简介那边的《CSS世界》的传送门是 https 的,然后访问不了…不知道是不是证书过期了.. http://www.cssworld.cn/ ,这个是可以的

  6. 寂寞看书说道:

    看了一下caniuse,indexDB在移动端的兼容性挺好的,感觉是能用用了

  7. 莫问说道:

    那么极端情况只能使用localStorage并且满了,还是一样吧

  8. BaoMax说道:

    只要清空缓存加载图片就会加载不出来,是否考虑存base64格式的图片,不存储blob,如果存blob的话localstorge应该也不会有问题吧,因为blob只是个url,blob:http://www.zhangxinxu.com/8d8ee0e5-a1c0-4942-a321-c084178fb414 这样

  9. 和尚爱敲钟说道:

    为什么刷新后图片加载不了,报错Not allowed to load local resource: blob:null/73379553-ad9a-4e92-bdea-5e58b62c1be0

    • 张 鑫旭说道:

      是我的demo页面,还是自己测试的页面?是http协议访问的吗?

    • 小宝说道:

      在本地的可以,用他的domo哪里是http访问的会有问题,自己写一个试试就好了啊

    • 小宝说道:

      补充,在关闭网页的时候createObjectURL 会自动释放,再次打开网页也会的不到你要的图片(虽然你的地址还在)

  10. u3u说道:

    > 开发者模式看了下,刷新居然图片不显示,原来是 disable cache 开启了,关了后正常显示了。这个能优化吗?

    我还发现上传后打开开发者工具切换到移动模式后刷新图片也不显示

    • 长江长江我是黄河说道:

      我发现移动状态下上传刷新没事。若是从pc状态上传切换到移动模式再刷新就会是你说的酱紫。从移动模式上传切到pc刷新也是。我觉得实际应用情况下没问题,手机就是手机,没有切换功能。具体能不能优化,期待中…

  11. 码农说道:

    开发者模式看了下,刷新居然图片不显示,原来是disable cache开启了,关了后正常显示了。这个能优化吗?

  12. dddd说道:

    jiu jiang zi