PaperJs图形设计开发-IndexedDB的应用

40 阅读2分钟

需求

  1. 保存当前图形设计项目到浏览器,用户刷新的时候不会丢弃图形设计页面的设计数据

功能

  1. 点击保存开启按钮,保存当前项目,刷新时存在项目则重载保存项目,否则创建空白页面
  2. 关闭保存按钮,刷新时新建空白项目

IndexedDB优点

  1. 适合大型图形数据和二进制(如图片、SVG、路径)
  2. 可存储结构化对象、大量数据
  3. 支持异步读写
  4. 适合复杂图形系统的数据持久化

IndexedDB缺点

  1. 原生API基于事件回调,使用复杂,代码冗杂严重,需要使用封装库idb或者Dexie.js提升体验
  2. Safari(IOS)兼容不好,存在各种Bug限制
  3. 在DevTools中查看数据很麻烦
  4. 不支持多设备同步、云同步
  5. 不适合高频实时数据操作

适用场景

  1. 存储图元结构复杂的对象(如Paperjs生成的JSON对象)
  2. 需要保存用户多个设计版本(只保存一个的话更推荐localstorage:localStorage只有5MB存储空间,大数据会setItem失败

实现方案

  1. 通过Redux,使用redux-persist继承IndexedDB实现全局状态持久化

实现步骤

IndexedDB简单应用

  1. 使用idb简化IndexedDB操作

    github.com/jakearchiba…

    npm install idb

  2. 新建工具文件 `services/indexedDBService.ts

    import { openDB } from "idb";
    
    const DB_NAME = "tcs_projects";
    const STORE_NAME = "projects";
    
    export const initDB = async () => {
      return await openDB(DB_NAME, 1, {
        upgrade(db) {
          if (!db.objectStoreNames.contains(STORE_NAME)) {
            db.createObjectStore(STORE_NAME);
          }
        },
      });
    };
    
    export const getProjectFromDB = async (key: string) => {
      const db = await initDB();
      return await db.get(STORE_NAME, key);
    };
    
    export const saveProjectToDB = async (key: string, data: any) => {
      const db = await initDB();
      await db.put(STORE_NAME, data, key);
    };
    

    保存当前修改

    saveProjectToDB("current_project", currentProjectData);
    

    刷新时加载数据库中项目

    const loadProjectFromDB = async () => {
      const project = await getProjectFromDB("current_project");
      if (project) {
        paper.project.importJSON(project as any);
      }
    };
    loadProjectFromDB();
    

一些尝试

  1. 将保存数据到IndexedDB放在刷新前的监听beforeunload中

    1. beforeunload 事件中只会等待同步操作,异步操作(如 awaitIndexedDBfetch 等)不会被等待执行完成。

优化点

  1. 不直接保存不可序列化的paper.project到indexedDB中,通过简化提取可序列化结构