模型本地存储

更新时间: 2021-06-08 16:45:21

还是之前那个模型查看的问题,有个模型50M,每次打开都需要从服务器上请求模型,速度太慢被老板吐槽了,所以考虑将模型存在本地,具体的方案呢,我选定了使用IndexedDB

我的思路是这样的:

  1. 首先在indexedDB查找有没有这个模型的数据存在
  2. 如果存在就将这个数据查询出来,加载本地的模型
  3. 如果不存在就从服务器请求模型数据,然后存在本地indexedDB

但是有两个问题:

  1. 从服务器请求到的模型怎么转换成blob存进indexedDB
  2. threejsgltfLoader需要提供的是一个确切的url地址

开始解决问题:

  • 首先解决怎么把从服务器请求到的模型转换成blob
axios({
  url:url,
  method: 'get',
  responseType:"blob"
}).then(res =>{
  let blob = res.data;
})
1
2
3
4
5
6
7

然后我们把这个数据存进IndexedDB

let id = "xxxxx" //这里随便弄的一个id

let indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
if(!indexedDB){
  console.log("不支持indexedDB")
}

let request = indexedDB.open('userModels');
let db
request.onupgradeneeded = (event) =>{
    console.log("数据库更新")
    db = event.target.result;
    // 判断是否有这个表
    if (!db.objectStoreNames.contains('models')) {
      // 创建表
      let objectStore;
      //使用id作为主键
      objectStore = db.createObjectStore('models', {
        // 主键
        keyPath: 'id'
      });
    }
}
request.onsuccess = (event) =>{
  //数据库打开成功
  db = event.target.result
  let transaction = db.transaction(['models'], 'readwrite');
  let objStore = transaction.objectStore('models');
  let req = objStore.get(id);
  req.onsuccess = (e) => {
    if (req.result) {
      //拿到数据
      console.log(req.result)
    } else {
      //未查询到数据
      axios({
        url:url,
        method: 'get',
        responseType:"blob"
      }).then(res =>{
        //将模型输入存进数据库
        let blob = res.data;
        db.transaction(['models'], 'readwrite').objectStore('models').add({id:id,blob:blob})
      })
    }
  }
};
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
  • 第二个问题,blob怎么转换成url

URL.createObjectURL() 静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象。

objectURL = URL.createObjectURL(object);
1

其中参数object是: 用于创建 URLFile 对象、Blob 对象或者 MediaSource 对象。

# 最终代码

解决了两个问题后,我们来写一个获取模型url的方法:

function getRealUrl(id,url){
  return new Promise((resolve,reject) => {
    let fileType = url.split('.')[url.split('.').length - 1]
    //查找数据库里有没有
    let indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
    if(!indexedDB){
      resolve(url)
      return false
    }
    let request = indexedDB.open('userModels');
    let db
    request.onupgradeneeded = (event) =>{
      console.log("数据库更新")
      db = event.target.result;
      // 判断是否有这个表
      if (!db.objectStoreNames.contains('models')) {
        // 创建表
        let objectStore;
        objectStore = db.createObjectStore('models', {
          // 主键
          keyPath: 'id'
        });
      }
    }
    request.onsuccess = (event) =>{
      console.log("数据库打开成功")
      db = event.target.result
      let transaction = db.transaction(['models'], 'readwrite');
      let objStore = transaction.objectStore('models');
      let req = objStore.get(id);
      req.onsuccess = (e) => {
        if (req.result) {
          console.log('已经查询到数据为:');
          console.log(req.result);
          let modelUrl = URL.createObjectURL(req.result.blob)
          db.close();
          resolve(modelUrl)
        } else {
          console.log('未查询到数据');
          axios({
            url:url,
            method: 'get',
            responseType:"blob"
          }).then(res =>{
            let blob = res.data;
            db.transaction(['models'], 'readwrite').objectStore('models').add({id:id,blob:blob})
            let modelUrl = URL.createObjectURL(blob)
            db.close();
            resolve(modelUrl)
          }).catch(() =>{
            db.close();
            resolve(url)
          })
        }
      }
    };
  })
}
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