浏览器数据库IndexedDB和前端多线程webWorker在3D场景中的实战应用

2022/8/24 2:24:58

本文主要是介绍浏览器数据库IndexedDB和前端多线程webWorker在3D场景中的实战应用,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

背景

1.IndexedDB 就是浏览器提供的本地数据库,它可以被网页脚本创建和操作。

2.在3D场景中模型数据很大,有可能存在数十万级的数据存储,大量数据存储在内存中会很容易导致内存溢出,因此采用indexedDB存储大量数据,减少占用浏览器内存引发的页面卡顿或者页面崩溃等性能问题

3.现有的浏览器数据储存方案都不适合储存大量数据:Cookie 的大小不超过4KB;LocalStorage 在 2.5MB 到 10MB 之间;IndexedDB的储存量视磁盘大小而定,具体说明如下:

 

 

 

 

 

 4.3D点云的文件格式.pcd,threejs加载3d点云的需要使用PCDLoader加载器,在PCDLoader.js源码中加载pcd文件需要遍及数十万级的数据并计算position,points的信息,这个过程耗时较长,会导致js阻塞从而页面会出现较长时间的卡顿,采用web worker增加多线程把计算position,points的信息这一步放在worker中执行,减少页面卡顿时间

 

 

 

 

 

 

 

 前端代码

1.indexedDB数据库

第一步:创建数据库

 1 var indexedDB = window.indexedDB;
 2     if (!indexedDB) {
 3       console.log('你的浏览器不支持IndexedDB');
 4     } else {
 5       var request = indexedDB.open("pcdpointsDB", 1);
 6       console.log('数据库创建.....');
 7       let db = null;
 8       request.onupgradeneeded = event => {
 9         db = (event as any).target.result;
10         //建表 名为person,主键为id
11         let store = db.createObjectStore('pcdInfo', {
12           keyPath: 'index'
13         });
14         store.createIndex('position', 'position', {
15           unique: false
16         });
17         store.createIndex('pcdPoints', 'pcdPoints', {
18           unique: false
19         });
20         store.createIndex('index', 'index', {
21           unique: false
22         });
23         store.createIndex('mesh', 'mesh', {
24           unique: false
25         });
26       }
27       request.onsuccess = event => {
28         db = (event as any).target.result;
29         console.log('数据库创建成功')
30         db.transaction(['pcdInfo'], 'readwrite').objectStore('pcdInfo').add({
31           index: index,
32           position: position,
33           pcdPoints: pcdPoints,
34           mesh:mesh.toJSON()
35         })
36         console.log('数据库新增数据......')
37         db.close()//关闭数据库
38       }
39       request.onerror = function (event) {
40         console.log('打开数据库失败');
41       }
42     }

第二步:获取数据库中的数据

 

 1 getIndexedDB(index) {
 2     return new Promise((resolve, reject) => {
 3       let request = indexedDB.open('pcdpointsDB');
 4       request.onsuccess = event => {
 5         console.log('数据库获取----open成功');
 6         let db = (event as any).target.result;
 7         var transaction = db.transaction(['pcdInfo']);
 8         let objectStore = transaction.objectStore('pcdInfo');
 9         let res = objectStore.get(index);
10         res.onsuccess = function (event) {
11           if (res.result) {
12             console.log(`${'数据库获取成功' + (index + 1)}`);
13             resolve(res.result)
14           } else {
15             console.log(`${'数据库获取---未获得数据记录' + (index + 1)}`);
16             resolve(null)
17           }
18           db.close()//关闭数据库
19 
20 
21         };
22         res.onerror = function (err) {
23           reject(err)
24         }
25 
26       }
27       request.onerror = function (err) {
28         reject(err)
29       }
30     })
31   }
通过async/await获取具体值
1 async loadPcdData() {
2       let result: any = await this.getIndexedDB(this.fileIndex);
3       let { pcdPoints = [],mesh } = result;
4         let loader = new THREE.ObjectLoader();
5         let parseMesh = loader.parse(mesh,()=>{});
6   }

第三步:删除数据库中的数据

 1 let request = indexedDB.open('pcdpointsDB');
 2     request.onsuccess = event => {
 3       console.log('数据库删除----open成功');
 4       let db = (event as any).target.result;
 5       var transaction = db.transaction(['pcdInfo'], 'readwrite');
 6       let objectStore = transaction.objectStore('pcdInfo');
 7       let res = objectStore.delete(index);
 8       res.onsuccess = function (event) {
 9         console.log(`${'数据库删除成功' + (index + 1)}`);
10         db.close()//关闭数据库
11 };

 

2.web worker多线程

  • web workers可以把耗时的计算放在非主线程里面。从而充分发挥电脑的性能;
  • 创建一个webworker子线程只需要一个脚本js文件url和new Worker(url),这个脚本文件就在新创建的子线程里加载和运行
    1 let worker=new Worker(workerUrl+'/worker.js')   //url是脚本文.件地址
    2       // 发送消息
    3       worker.postMessage(res);
    4       worker.onmessage = function(event){
    5         let { pcdPoints,position,color,normal  } =event.data;
    6         worker.terminate() //关闭主进程
    7 }

     

  • 子进程中的执行环境跟主线程环境是隔离的,子进程的全局环境是self或者this,处理完的数据通过self.postMessage传递给主线程,主线程通过worker.onmessage接收。
    1 onmessage = function (event) {
    2   let { pointsPCD, dataview,url } = event.data;
    3   let pcdResult = setPcdloaderResult(pointsPCD, dataview);
    4   postMessage(pcdResult);
    5   this.close() //关闭线程
    6 }

     

  • worker.postMessage(参数)参数就是传递给子线程需要处理的数据,

    注意:1.函数方法或者类无法传递

     

     

     

     

     

  • Sources下的Page可以看到worker.js脚本文件,释放worker子线程就会消失;worker子线程会耗费大量的资源,而且不会自动的被释放,通过上述代码创建完之后,如果不需要了,我们需要手动释放。
  • 释放worker子线程有两种方法。
    子线程及时关闭 this.close()或者self.close();
    主线程关闭worker.terminate()

开发过程中的问题验证

  1.场景使用:worker.js有可能需要引入模块化的包,比如import或者require,目前导入模块包会导致脚本文件不执行,无法查看报错原因

  技术方案:采用worker-loader插件,webpack配置

npm I –D worker-loader

1 {
2   test: /\.testWorker\.js$/,
3   use: { loader: "worker-loader" },
4 },

入口文件配置

1    entry: {
2         worker: './src/utils/worker.js',
3     },

 

 

 

 2.3d点云中的mesh模型对象存储到indexedDB时,从indexedDB中获取到对象之后怎么反解析成Mesh对象

技术方案实现:

  • mesh继承自Object3D,其中有一个方法,toJSON()可以以json格式返回对象的数据;
  • 将mesh对象.toJSON()存储到indexedDB,拿到jsonmesh使用ObjectLoader解析出来
  • 1 let jsonmesh=mesh.toJSON();
    2 let loader = new THREE.ObjectLoader();
    3 let parseMesh = loader.parse(mesh,()=>{});
    4 console.log(parseMesh)

     

其他导致内存溢出的情况

  • 避免console.log打印这些数十万级的position,pcdPoints数组,非常消耗性能
  • 全局环境中避免过多存储position,pcdPoints等全局变量,非常消耗性能,可以在indexedDB获取你需要的数据,在函数中作为参数传递,函数执行完毕就会被回收销毁
  • 通过memory查看内存使用情况

     

     

     

     

     



这篇关于浏览器数据库IndexedDB和前端多线程webWorker在3D场景中的实战应用的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程