localStorage不是同步的吗?😓怎么还能异步使用?同事:仔细看看?

3,913 阅读2分钟

最近接手了一个新项目,打开一个文件时,我看到了一行让我一头雾水的代码:

localStorage.get().then(...)

“这tm谁写的代码?”我心里想着,localStorage 不是同步的吗?怎么会有 .then() 这样的用法?我忍不住找旁边的同事吐槽了一番。

同事笑着说:“仔细看一下。”

瞬间,我意识到我的尴尬:这并不是 localStorage,而是 localForage!这俩单词也太像了吧!我不禁会心一笑,心里暗想,看来我得好好了解一下这个库。

什么是 LocalForage?

LocalForage 是一个用于在浏览器中存储数据的 JavaScript 库,旨在提供类似于本地存储的 API,但支持更多的数据类型和更大的存储空间。目的是简化在 Web 应用中使用异步存储的过程。

在很多 Web 应用中,开发者需要在用户的浏览器中存储数据,比如用户设置、游戏进度或者离线数据等。传统的 localStoragesessionStorage 只支持字符串存储,而且存储空间有限。LocalForage 通过封装 IndexedDB、WebSQL 和 localStorage,使得开发者可以使用简单的 API 来处理不同类型的数据(如对象和数组),并且异步操作不会阻塞主线程。

使用方式

  1. 安装

    可以通过 npm 安装 LocalForage:

    npm install localforage
    

    或者直接在 HTML 文件中引入:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/localforage/1.10.0/localforage.min.js"></script>
    
  2. 基本用法

    LocalForage 提供了一系列简单的方法来存储、获取和删除数据。

    • 设置数据

      localforage.setItem('key', { name: 'Alice', age: 25 })
        .then(function () {
          console.log('Data saved successfully!');
        })
        .catch(function (err) {
          console.error('Error saving data:', err);
        });
      
    • 获取数据

      localforage.getItem('key')
        .then(function (value) {
          console.log('Retrieved data:', value);
        })
        .catch(function (err) {
          console.error('Error retrieving data:', err);
        });
      
    • 删除数据

      localforage.removeItem('key')
        .then(function () {
          console.log('Data removed successfully!');
        })
        .catch(function (err) {
          console.error('Error removing data:', err);
        });
      
    • 清空数据

      localforage.clear()
        .then(function () {
          console.log('All data cleared!');
        })
        .catch(function (err) {
          console.error('Error clearing data:', err);
        });
      
    • 配置选项

    LocalForage 允许开发者在初始化时进行配置,例如设置数据库名称、版本等:

    localforage.config({
      driver: localforage.INDEXEDDB, // 使用的存储驱动
      name: 'myApp',
      version: 1.0,
      storeName: 'keyvaluepairs', // 存储的表名
      description: 'Some description'
    });
    

源码解读

目录

image.png

三个driver

三个driver都会导出如下对象,然后在LocalForage类中使用 image.png

constructor中setDriver

LocalForage类中会设置setDriver,在其中初始化一些参数

self._driver = driver._driver;
setDriverToConfig();
self._wrapLibraryMethodsWithReady();
self._initDriver = initDriver(supportedDrivers);

ready之后执行self._initDriver()

    ready(callback) {
        const self = this;

        const promise = self._driverSet.then(() => {
            if (self._ready === null) {
                self._ready = self._initDriver();
            }

            return self._ready;
        });

        executeTwoCallbacks(promise, callback, callback);
        return promise;
    }

_initDriver中执行extendSelfWithDriver扩展对象方法

extendSelfWithDriver之后就会有getItem等方法了

function extendSelfWithDriver(driver) {
    self._extend(driver);
    setDriverToConfig();

    self._ready = self._initStorage(self._config);
    return self._ready;
}

以封装getItem为例子

以localStorage中为例
this就是new LocalForage(),会等ready之后执行对应的localStorage.getItem操作,然后返回promise

function getItem(key, callback) {
    var self = this;

    key = normalizeKey(key);

    var promise = self.ready().then(function() {
        var dbInfo = self._dbInfo;
        var result = localStorage.getItem(dbInfo.keyPrefix + key);

        // If a result was found, parse it from the serialized
        // string into a JS object. If result isn't truthy, the key
        // is likely undefined and we'll pass it straight to the
        // callback.
        if (result) {
            result = dbInfo.serializer.deserialize(result);
        }

        return result;
    });

    executeCallback(promise, callback);
    return promise;
}