├── .gitignore ├── package.json ├── README.md ├── main.js └── src ├── worker.js ├── virtual-list.html └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "worker", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "main.js", 6 | "scripts": { 7 | "start": "node main.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "koa": "^2.13.1", 14 | "koa-router": "^10.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 前端海量数据处理 2 | 3 | 针对前端处理海量数据,写了个人的解决方案! 4 | 5 | ## 虚拟列表 6 | 7 | [demo 文件](./src/virtual-list.html) 8 | 9 | 10 | 11 | ## 虚拟列表 + webWorker + indexDB 实现 12 | 13 | 14 | 15 | ### 启动步骤: 16 | 17 | 1. npm i 18 | 19 | 2. npm start 20 | 21 | 3. 访问 http://localhost:9527 -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | const Koa = require('koa') 2 | const Router = require('koa-router'); 3 | const fs = require('fs/promises') 4 | 5 | const app = new Koa() 6 | const router = new Router() 7 | 8 | // 实现的虚拟列表 9 | router.get('/', async (ctx, next) => { 10 | const content = await fs.readFile('./src/index.html', { encoding: 'utf8' }) 11 | ctx.body = content 12 | }) 13 | 14 | // worker 15 | router.get('/worker.js', async (ctx, next) => { 16 | const content = await fs.readFile('./src/worker.js') 17 | ctx.body = content 18 | }) 19 | 20 | const port = 9527 21 | 22 | app.use(router.routes()).use(router.allowedMethods()).listen(port) 23 | 24 | console.log(`预览:`, `\x1B[36mhttp://localhost:${port}\x1B[0m`) 25 | -------------------------------------------------------------------------------- /src/worker.js: -------------------------------------------------------------------------------- 1 | const databaseName = 'virtualList' 2 | let db 3 | let isFinished = false 4 | 5 | const controlDatabase = db => { 6 | db.onversionchange = () => { 7 | postMessage({ type: 'close', msg: '只能打开一个页面哦,请关闭其他页面再刷新哦' }) 8 | db.close() 9 | } 10 | } 11 | 12 | // 创建数据库 13 | const createDatabase = async () => { 14 | let version = 1 15 | const databases = await indexedDB.databases() 16 | const preDatabase = databases.find(({ name }) => name === databaseName) 17 | if (preDatabase) version = preDatabase.version + 1 18 | 19 | // indexedDB.deleteDatabase(databaseName) 20 | const database = indexedDB.open(databaseName, version) 21 | return new Promise((f, r) => { 22 | database.onsuccess = e => controlDatabase(e.target.result) 23 | database.onupgradeneeded = f 24 | database.onerror = r 25 | }) 26 | } 27 | 28 | // 创建表 29 | const createTable = db => { 30 | return new Promise((f, r) => { 31 | try { 32 | db.deleteObjectStore('list') 33 | }catch (e) { 34 | console.log(e) 35 | } 36 | const table = db.createObjectStore('list', { keyPath: 'id' }) 37 | 38 | table.transaction.oncomplete = () => { 39 | const store = db.transaction('list', 'readwrite').objectStore('list') 40 | 41 | let i = 0 42 | while (i < 100000) { 43 | store.add({ id: i++, num: Math.random() }) 44 | } 45 | 46 | f(i) 47 | isFinished = true 48 | } 49 | }) 50 | } 51 | 52 | // 检索 53 | const search = ({ size, start }) => { 54 | if (!isFinished) return [] 55 | 56 | return new Promise((f, r) => { 57 | const store = db.transaction('list', 'readonly').objectStore('list') 58 | const range = IDBKeyRange.bound(start, start + size) 59 | const list = [] 60 | 61 | store.openCursor(range).onsuccess = ({ target: { result } }) => { 62 | if (!result) { 63 | return f(list) 64 | } 65 | 66 | list.push(result.value) 67 | result.continue() 68 | } 69 | }) 70 | } 71 | 72 | const start = async () => { 73 | const { target: { result } } = await createDatabase() 74 | const data = await createTable(db = result) 75 | postMessage({ 76 | type: 'ok', 77 | data 78 | }) 79 | } 80 | 81 | addEventListener('message', async ({ data }) => { 82 | const result = await search(data) 83 | postMessage(result) 84 | }) 85 | 86 | start() -------------------------------------------------------------------------------- /src/virtual-list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 虚拟列表 7 | 25 | 26 | 27 |
28 |
38 |
39 |
40 |
{{ item }}
41 |
42 |
43 |
44 | 95 | 96 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 前端海量数据 9 | 30 | 31 | 32 |
33 |
45 |
46 |
47 |
{{ `${item.id}-------------${item.num}` }}
48 |
49 |
50 |
51 | 121 | 122 | --------------------------------------------------------------------------------