当前位置:   article > 正文

简介 IndexedDB 及详解 IndexedDB 在实际项目中可能存在的问题与解决方案_indexeddb难点

indexeddb难点
简介IndexedDB
详细文档请参看 MDN 文档链接
IndexedDB能做什么:
  • 它真的很能存东西! 对比cookie, local storeage, session storage 等受到大小限制的web存储方式, IndexedDB在理论上并无大小限制只与本地的磁盘相关。 这也是选择它作为web本地存储工具最大的理由。
  • 完整的API文档( 虽然大部分是英文Orz), 不懂的直接翻文档。 3. 异步, 这意味着不会锁死浏览器, 也意味着在进行多库多表操作时会很麻烦, 下文中会详细介绍。

废话不多说, 让我们直接用一个实际的例子来看 IndexedDB 如何使用。( PS: 这一部分算是对 IndexedDB 的简介和科普, 本文真正的核心在后面, 如果不想看科普可以直接跳到后面)

IndexedDB 需要理解以下几个重要的概念:
  • 数据库: IDBDatabase
  • 对象仓库: IDBObjectStore( 我更愿意称之为: 表)
  • 索引: IDBIndex
  • 事务: IDBTransaction
  • 操作请求: IDBRequest
  • 指针: IDBCursor

实际项目中一般正常的流程为:

开库→ 建表→ 创建索引→ 存入 / 删除数据→ 获取数据

这里我们先使用文档中的一个例子( 后面再来说哪里存在问题)

  const dbName = "the_name";

  const customerData = [{
    ssn: "444-44-4444",
    name: "Bill",
    age: 35,
    email: "bill@company.com"
  }, {
    ssn: "555-55-5555",
    name: "Donna",
    age: 32,
    email: "donna@home.org"
  }];

  var request = indexedDB.open(dbName, 2);

  request.onsuccess = function(event) {
    var db = event.target.result;
    // todo
  };

  request.onupgradeneeded = function(event) {
    var db = event.target.result;

    var objectStore = db.createObjectStore("customers", {
      keyPath: "ssn"
    });

    objectStore.createIndex("name", "name", {
      unique: false
    });
    objectStore.createIndex("email", "email", {
      unique: true
    });

    objectStore.transaction.oncomplete = function(event) {
      var customerObjectStore = db.transaction("customers", "readwrite").objectStore("customers");
      customerData.forEach(function(customer) {
        customerObjectStore.add(customer);
      });
    };
  };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
开库: indexedDB.open(库名, 数据库版本)
注意事项:
  1. 库名必填, 版本非必填
  2. 版本号如果不填则, 默认打开当前版本的数据库
  3. 这个函数的回调即上文中提到的重要概念之一 ** IDBRequest **
IDBRequest:
  通常来说我们经常会用到的函数 
  onsuccess: 成功回调, 通俗的讲就是: 你可以开始页面的其他操作了。 
  onupgradeneeded: 升级数据库回调, 通俗的讲就是: 稳一手, 再操作。
  • 1
  • 2
  • 3
注意事项
  1. onupgradeneeded 优先于 onsuccess 触发
  2. 当仅当数据库版本号 发生变化的时候触发 onupgradeneeded。 换句话说, 如果当前版本号为2。
    1. indexedDB.open(‘myDB’) 只会触发 onsuccess。
    2. indexedDB.open(‘myDB’, 3) 同时触发 onsuccess 与 onupgradeneeded。 优先级参看第1条。
    3. indexedDB.open(‘myDB’, 1) 什么都不会发生: )
  3. 当仅当触发 onupgradeneeded 时 可以对 IDBObjectStore 也就是表进行增、 删、 改。
建表:
event.target.result.createObjectStore('myList', {
  keyPath: 'id',
  autoIncrement: true
})
  • 1
  • 2
  • 3
  • 4
注意事项:
  1. 第一个参数表名, 第二个参数 keyPath 主键名, autoIncrement 主键是否自增。
  2. 这里有个很隐晦的坑, 如果设置主键自增, 那么在创建索引的时候可以无需传入主键名, 反之则需要传入主键名, 后续的例子中会呈现。
  3. event.target.result 是函数 onupgradeneeded 的返回值, 同时也是上文提到的重要概念之一 IDBDatabase 以及它的方法 IDBTransaction
IDBDatabase
这个对象就是通常意义上的数据库本身, 我们可以通过这个对象进行表的增、 删, 以及事物 IDBTransaction。
  • 1
IDBTransaction
在IndexedDB中所做的所有事情总是发生在事务的上下文中, 表示与数据库中的数据的交互。
IndexedDB中的所有对象—— 包括对象存储、 索引和游标等都与特定事务绑定。
因此, 在事务之外不能执行命令、 访问数据或打开任何东西。( PS: 通俗的意义上讲就是...此路是我开, 此树是我栽, 要想读写数据, 请过我这关 ̄□ ̄)
  • 1
  • 2
  • 3
创建索引
objectStore.createIndex("name", "name", {
  unique: false
});
  • 1
  • 2
  • 3
注意事项
  1. 第一个和第二个参数均是索引名, unique 如果为true, 则索引将不允许单个键有重复的值。
  2. objectStore 即 ** IDBObjectStore ** 也就是表。
  3. 表数据的增、 删、 改可以放在 onupgradeneeded 或 onsuccess 中进行( 推荐在 onsuccess 中), 但是对于表本身和索引的修改仅能在 onupgradeneeded 中。
IDBObjectStore
这个就是表了, 它所包含的方法很多都是实际项目中经常用到的比如:
add() 写入数据
createIndex() 创建索引
delete() 删除键
index() 获取索引
get() 检索值
getAll() 检索所有的值
不做过多叙述, 详见文档。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
注意事项
  1. 再次重复一遍, 这个对象包含的方法涵盖了对表本身以及数据的操作。 对本身的操作请在 onupgradeneeded 中, 对数据的操作请在 onsuccess 中。
存入 / 删除数据
还记得 IDBTransaction 和 IDBObjectStore 吗? 此时绕不开这俩货
虽说真正执行数据操作的函数是 objectStore.add() 等等, 但请在事物IDBTransaction中获取IDBObjectStore对象。
  • 1
  • 2
获取数据
同上, 原谅我, 懒得写: ) 了
  • 1

正片开始

如果光看上面的例子, 其实 IndexedDB 并不复杂。 然而在实际项目中却会遇到大量的问题, 主要集中在1个问题所引发更多的小问题。

这个问题就是:多库或多表的同时操作。 (这也是本文真正的想要表达的东西)

在实际项目中, 不太可能一张表就写完所有数据, 有过数据库操作经验的老哥应该明白。 通常我们需要关联两张甚至多张表, 即一张表的键值, 是另一张表的键或主键, 所以我们可以关联这两张表, 而不必要也不需要在一张表里写完所有数据。

由于 IndexedDB 是异步实现, 所以首先要明确我们究竟在操作哪张表, 建立了哪个事物, 这个链接完成了吗? 等等。

明确上述问题才能解决: 为何索引变动会蛋疼到难以言喻? 为什么首次进入浏览器创建两张表再写入数据会失效? 等一系列问题。

话不多说, 先上代码, 下面是我对 IndexedDB 的简单封装用作讲解。

class localDB {
    constructor(openRequest = {}, db = {}, objectStore = {}) {
        this.openRequest = openRequest;
        this.db = db;
        this.objectStore = objectStore;
        Object.getOwnPropertyNames(this.__proto__).map(fn => {
            if (this.__proto__[fn] === 'function') {
                this[fn] = this[fn].bind(this);
            }
        })
    }
    openDB(ops, version) {
        let db = Object.assign(new defaultVaule('db'), ops);
        this.openRequest = !!version ? window.indexedDB.open(db.name, version) : window.indexedDB.open(db.name);
    }
    onupgradeneeded() {
        const upgradeneed = new Promise((resolve, reject) => {
            this.openRequest.onupgradeneeded = (event) => {
                this.db = event.target.result;
                resolve(this);
            }
        })
        return upgradeneed;
    }
    onsuccess() {
        const success = new Promise((resolve, reject) => {
            this.openRequest.onsuccess = (event) => {
                this.db = event.target.result;
                resolve(this);
            }
        })
        return success;
    }
    createObjectStore(ops) {
        let list = Object.assign(new defaultVaule('list'), ops);
        const store = new Promise((resolve, reject) => {
            this.objectStore = this.db.createObjectStore(list.name, {
                keyPath: list.keyPath,
                autoIncrement: list.auto
            });
            resolve(this);
        })
        return store;
    }
    createIndex(ops, save) {
        const store = new Promise((resolve, reject) => {
            ops.map(data => {
                let o = Object.assign(new defaultVaule('idx'), data);
                this.objectStore.createIndex(o.name, o.name, {
                    unique: o.unique
                })
            })
            resolve(this);
        })
        return store;
    }
    saveData(type = {}, savedata) {
        let save = Object.assign(new defaultVaule('save'), type);
        const transAction = new Promise((resolve, reject) => {
            let preStore = this.objectStore = this.getObjectStore(save);
            preStore.transaction.oncomplete = (event) => {
                let f = 0;
                let store = this.objectStore = this.getObjectStore(save);
                savedata.map(data => {
                    let request = store.add(data);
                    request.onsuccess = (event) => {
                        // todo 这里相当于每个存储完成后的回调,可以做点其他事,也可以啥都不干,反正留出来吧 :)
                    }
                    f++;
                })
                if (f == savedata.length) {
                    resolve(this);
                }
            }
        })
        return transAction;
    }
    getData(ops, name, value) {
        let store = this.getObjectStore(ops);
        let data = new Promise((resolve, reject) => {
            store.index(name).get(value).onsuccess = (event) => {
                event.target.result ? resolve(event.target.result) : resolve('暂无相关数据')
            }
        })
        return data;
    }
    getAllData(ops) {
        let store = this.getObjectStore(ops);
        let data = new Promise((resolve, reject) => {
            store.getAll().onsuccess = (event) => {
                event.target.result ? resolve(event.target.result) : resolve('暂无相关数据')
            };
        })
        return data;
    }
    deleteData(ops,name) { // 主键名
        let store = this.getObjectStore(ops);
        store.delete(name).onsuccess = (event) => {
            console.log(event);
            console.log(this);
        }
    }
    updateData(ops, index, lastValue, newValue) { // index 索引名 lastValue 需要修改的值 newValue 修改后的值
        let store = this.getObjectStore(ops);
        let data = new Promise((resolve, reject) => {
            store.openCursor().onsuccess = (event) => {
                const cursor = event.target.result;
                if (cursor) {
                    if (cursor.value[index] == lastValue) {
                        let updateData = cursor.value;
                        updateData[index] = newValue;
                        let updateDataRequest = cursor.update(updateData)
                        updateDataRequest.onsuccess = () => {
                            resolve('更新完成');
                        };
                    }
                    cursor.continue();
                } else {
                    resolve('找不到指定的值');
                }
            }
        })
        return data;
    }
    getObjectStore(ops) {
        return this.db.transaction(ops.name, ops.type).objectStore(ops.name);
    }
    clear(ops) {
        let clear = new Promise((resolve, reject) => {
            this.getObjectStore(ops).clear();
            resolve(this);
        })
        return clear
    }
    deleteStore(name) {
        let store = new Promise((resolve, reject) => {
            this.db.deleteObjectStore(name);
            resolve(this);
        })
        return store;
    }
    updateDB() {
        let version = this.db.version;
        let name = this.db.name;
        let update = new Promise((resolve, reject) => {
            this.closeDB();
            this.openDB({
                name: name
            }, ++version);
            resolve(this);
        })
        return update;
    }
    closeDB() {
        this.db.close();
        this.objectStore = this.db = this.request = {};
    }
}

class defaultVaule {
    constructor(fn) {
        if (typeof this.__proto__[fn] === 'function') {
            return this.__proto__[fn]();
        }
    }
    db() {
        return {
            name: 'myDB',
        }
    }
    list() {
        return {
            name: 'myList',
            keyPath: 'id',
            auto: false,
        }
    }
    idx() {
        return {
            name: 'myIndex',
            unique: false,
        }
    }
    save() {
        return {
            name: 'myList',
            type: 'readwrite'
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190

模拟一下用户在使用的时候遇到的场景:

1、 打开浏览器→ 因为是首次进入浏览器, 这时必然触发 onsuccess 与 onupgradeneeded。 此时我们在 onupgradeneeded 中建表建立索引, 存入或者不存入初始数据之类的操作, 当然还是根据具体的业务逻辑来。

let db = new localDB();

db.openDB(DB);

db.onsuccess().then(data => {
    console.log('onsuccess');
    // todo
})

db.onupgradeneeded().then(data => {
    console.log('onupgradeneeded');
    // todo
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

此处, 如果只建立一张表, 再存入数据, 那写法可能是多样的, 例如

db.onupgradeneeded().then(data => {
    data.createObjectStore(MAINKEY).then(data => {
        data.createIndex(ITEMKEY).then(data => {
            console.log('表和索引创建完毕')
        })
    })
})

db.onsuccess().then(data=>{
    data.saveData(SAVETYPE, person).then(data => {
        console.log('数据写入完毕');
    })
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这样做, 不是不可以, 但是没有必要, 既然用了promise就不要搞成无限嵌套 推荐使用 async / await 看上去更美滋滋。

async function showDB(db) {
    try {
        await db.createObjectStore(MAINKEY);
        await db.createIndex(ITEMKEY);
        return db;
    } catch (err) {
        console.log(err);
    }
}

db.onupgradeneeded().then(data => {
    console.log('onupgradeneeded');
    showDB(data).then(data=>{
        console.log('表以及索引创建完毕')
    })
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

用同步写异步, 逻辑层面更清晰一点。 上述代码其实回归本质依然是

var localIDB = function() {
  this.request = this.db = this.objectStore = {};
}

localIDB.prototype = {
  openDB: function(ops, callback) {
    var ops = this.extend(ops, this.defaultDB());
    this.request = window.indexedDB.open(ops.name, ops.version);
        return this;
  },
  onupgradeneeded: function(callback) {
    var _this = this;
    this.request.onupgradeneeded = function(event) {
      _this.db = event.target.result;
      callback && callback(event, _this);
    }
    return this;
  },
  onsuccess: function(callback) {
    var _this = this;
    this.request.onsuccess = function(event) {
      _this.db = event.target.result;
      callback && callback(event, _this);
    }
    return this;
  }
}

var db = new localDB();
db.open().onupgradeneeded(function(event,data){
    // todo event是这个事件,data指向对象本身
}).onsuccess(function(event,data){
   // todo 同上
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

其实看上去差不多对不对, 但如果建立两张表, 并分别写入数据呢? async / await 就显得更清晰了

async function showDB(db) {
    try {
        await db.createObjectStore(MAINKEY); 
        await db.createIndex(ITEMKEY);
        let success = await db.onsuccess();     // 第一次 触发 onsuccess
        await success.saveData(SAVETYPE, person); // 第一次 写入数据
        await success.updateDB(); // 升级数据库 
        await success.onupgradeneeded(); // 第二次 触发 onupgradeneeded
        await success.createObjectStore(MAINKEY1); 
        await success.createIndex(ITEMKEY1);
        let success1 = await success.onsuccess(); // 第二次 触发 onsuccess
        await success1.saveData(SAVETYPE1, personDetail); // 第二次 写入数据
        return success1;
    } catch (err) {
        console.log(err);
    }
}

db.onupgradeneeded().then(data => {
    console.log('onupgradeneeded');
    showDB(data).then(data => {
        console.log('两张表,分别写入数据完成');
    })
})

db.onsuccess().then(data=>{
     console.log('数据库加载完毕');
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
这里有个值得注意的地方:
  • 当用户第一次进入时开库建表触发的是 onupgradeneeded 以及完成开库建表操作的 onsuccess。 实际情况也确实如此, 但我们在 onupgradeneeded 里面执行了函数 showDB(), 于是问题来了:
  • 问:那么, showDB() 的返回是什么呢?
  • 答: 执行了saveData的对象db本身。
  • 问:为什么最外层的 db.onsuccess().then(data => { console.log('数据库加载完毕'); }) 没有被触发呢?
  • 答:
    • async / await 中第一个 onsuccess 的 callback 用来执行写入操作以及之后的升级, 第二次建表等等。
    • 通俗的来讲大概就是: 这是一个异步的且连贯的操作, 外层的 onsuccess 根本没机会插手的机会。
    • 当用户第二次进入时( 刷新页面之列的操作), 因为版本号没有变化所以只会触发 onsuccess。 这个时候就会触发最外层的 onsuccess 了。
让我们举一个简单的查询例子:

按照上文, 我们已经有一个数据库
表1:
在这里插入图片描述
表2:
在这里插入图片描述

假设: 我们需要从表1中拿到秀儿的uid, 然后用uid去表2中获取秀儿的具体信息。

// html部分代码
<button onclick="getXiuer()"></button>
// js 部分
// 可以如下嵌套的方式
function getXiuer() {
    let uid;
    let obj;
    db.getData({
        name: 'person',
        type: 'readonly',
    }, 'name', '秀儿').then(data => {
        console.log(data)
        uid = data.uid;
        db.getData({
            name: 'detail',
            type: 'readonly',
        }, 'uid', uid).then(data => {
            console.log(data);
        });
    });
}
// 也可以如下async/await的方式
funtion getXiuer() {
    getXiuerWait(db).then(data => {
        console.log(data);
    })
}
async function getXiuerWait(db) {
    try {
        let uid;
        let data = await db.getData({
            name: 'person',
            type: 'readonly',
        }, 'name', '秀儿');
        let result = await db.getData({
            name: 'detail',
            type: 'readonly',
        }, 'uid', data.uid);
        return result;
    } catch (err) {
        console.log(err);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

结果如图所示:
在这里插入图片描述
获取所有数据的返回值是一个数组

db.getAllData({
    name: 'detail',
    type: 'readonly'
}).then(data => {
    console.log(data)
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如图所示:
在这里插入图片描述
想必聪明的你已经发现, 其实存入数据库的值可以是多种多样的, 字符串、 数字、 布尔值、 数组都是可以的。 长度其实也没有特别的限制( 反正我连base64的本地图片都存了 o(╥﹏╥) o)

假设: 我们需要修改一个已经存在的值( 把索引为 age 的值由 60 改为 17)

db.updateData(SAVETYPE1, 'age', 60, 17).then(data => {
    console.log(data)
})
  • 1
  • 2
  • 3

结果如图所示:
在这里插入图片描述
在这里插入图片描述

总结

IndexedDB只要理清楚开篇的几个概念即:

  • 数据库: IDBDatabase
  • 对象仓库: IDBObjectStore
  • 索引: IDBIndex
  • 事务: IDBTransaction
  • 操作请求: IDBRequest
  • 指针: IDBCursor

以及异步返回的时机, 此时此刻在操作哪张表, 可以触发哪几个函数, 其实是一个蛮好用的工具。

现在再来回答 索引的修改应该如何进行?

答:

  1. 要么在一开始就设计好索引, 避免修改( 这是句废话(ಥ﹏ಥ))
  2. 如果无可避免, 那么可以备份当前索引( getAllData里应有尽有)。 再通过升级数据库版本触发 onupgradeneeded 删除以前的表, 创建新的表。 然而这里又有一个隐晦的坑 o(╥﹏╥) o *
    如果用户刷新页面, 也就是说仅触发 onsuccess。 那么, 自然要升级一次版本号, 在这次升级中触发的 onupgradeneeded 中, 让我们来看看索引的建立
var objectStore = db.createObjectStore("customers", { keyPath: "ssn" });
    objectStore.createIndex("email", "email", { unique: true });
  • 1
  • 2
  • objectStore 也就是 IDBObjectStore 对象的获取是通过创立主键来达成的。
  • 或者objectStore 也可以通过事物 IDBTransaction 来获取。
  • 但这里有个问题 IDBTransaction 尽量在 onsuccess 中,而主键创建在 onupgradeneeded 中, 僵住了…

所以我们的代码可能看上去可能应该是这样

// 懒得写 async/await 版本的了 !!(╯' - ')╯︵ ┻━┻ 好累!反正就这意思
db.updateDB().then(data => {
    data.onupgradeneeded().then(data => {
        data.deleteStore('detail').then(data => {
            console.log(data);
            // 建表 建包含新索引的索引 再存入数据
        })
    })
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

看到了吗? 这是人干的事儿吗? 第一次开库建表的时候就可以弄好的事情, 不要搞成这样…

差不多就是这样了, 当只有1张表的时候, 事情很轻松, 但是多张表的时候笑容渐渐变态…

好了, 有啥不清楚的, 可以留言, 如果看到了, 而且我会的话, 肯定会回答。

最后附上测试用的数据

const DB = {
	name: 'student',
	version: 1
}

const MAINKEY = {
	name: 'person',
	keyPath: 'id',
	auto: true,
}

const ITEMKEY = [{
	name: 'name',
	unique: false,
}, {
	name: 'uid',
	unique: true,
}]

const person = [{
	name: '秀儿',
	uid: '100',
}, {
	name: '张三',
	uid: '101',
}, {
	name: '李敏',
	uid: '102',
}, {
	name: '日天',
	uid: '103',
}]

const SAVETYPE = {
	name: 'person',
	type: 'readwrite',
}

const MAINKEY1 = {
	name: 'detail',
	keyPath: 'uid',
	auto: false,
}

const ITEMKEY1 = [{
	name: 'uid',
	unique: false,
}, {
	name: 'age',
	unique: false,
}, {
	name: 'sex',
	unique: false,
}, {
	name: 'desc',
	unique: false,
}, {
	name: 'address',
	unique: false,
}]

const personDetail = [{
	uid: '102',
	age: '18',
	sex: '♀',
	desc: '女装大佬',
	address: ["遥远的地方"],
}, {
	uid: '103',
	age: '18',
	sex: 'man',
	desc: 'rua!',
	address: '{"test":"123","more":"asd"}',
}, {
	uid: '100',
	age: 'unknown',
	sex: 'unknown',
	desc: '666',
	address: true,
}, {
	uid: '101',
	age: 60,
	sex: 'man',
	desc: '路人甲',
	address: true,
}]

const SAVETYPE1 = {
	name: 'detail',
	type: 'readwrite',
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/507313
推荐阅读
相关标签
  

闽ICP备14008679号