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

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

时间:2022-08-22 19:36:00浏览次数:107  
标签:IndexedDB indexedDB console 数据库 worker webWorker let 多线程 event

背景

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,indexedDB,console,数据库,worker,webWorker,let,多线程,event
From: https://www.cnblogs.com/wsqspace/p/16613943.html

相关文章

  • 多线程的爬取
    #导入一个请求的模块importjsonimporttimefromconcurrent.futures.threadimportThreadPoolExecutorfromurllib.parseimporturlencodeimportrequests#图片的名字......
  • 异步和多线程区别
    异步和多线程区别异步和多线程有什么区别其实,异步是目的,而多线程是实现这个目的的方法。异步是说,A发起一个操作后(一般都是比较耗时的操作,如果不耗时的操作就没有必要异步......
  • springboot多线程环境下注入bean空指针问题解决
    多线程环境下注入bean会出现空指针了..我是怎么知道这个bean有有没有在启动的时候注入进来的呢?用于指示bean包含在SpringApplication中时应该运行的接口。多个CommandL......
  • 多线程实现生产和消费
    若⼲个⽣产者在⽣产产品,这些产品将提供给若⼲个消费者去消费,为了使⽣产者和消费者能并发执⾏,在两者之间设置⼀个能存储多个产品的缓冲区,⽣产者将⽣产的产品放⼊缓冲区中,消......
  • java多线程
    一、定义很多人应该对进程,线程,程序这几个概念混淆.程序指什么?简而言之,程序就是代码,用不同语言编写的代码;什么是进程?进程就是表示程序一次完整的执行;线程指的是,在......
  • 多线程.总结
    packageoop.dxcgaoji;importcom.sun.org.apache.xpath.internal.functions.FuncTrue;importjava.util.concurrent.Callable;importjava.util.concurrent.ExecutionExce......
  • 多线程.线程池
    ExecutorService和ExecutorsExecutorService:真正的线程池接口。常见子类ThreadPoolExecutorvoidexecute(Runnablecommand):执行任务/命令,没有返回值,一般用来执行Run......
  • 多线程.Lock锁
    ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentantLock,可以显式加锁、释放锁synchronized与Lock的对比......
  • 多线程.死锁
    多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形。某一个同步块同时拥有“两个以上对......
  • 使用多线程实现四个窗口共同卖票
    创建票对象/***projectName:testSpring**@author:*time:2022/8/2023:04*description:票对象,这里实现Runnable方法来重写Run方法*/publicclassTicketim......