【免费下载链接】maptoposter-online
✨❤️🔥Turn the cities you love into stunning designs
MapPoster Online 是一款在浏览器里把城市变成艺术海报的工具:选城市、调主题,一键导出高清地图海报。它要抓取几十万条道路坐标、还要在本地渲染整张地图——如果都在主线程跑,页面早就假死了。这篇文章带你拆解它如何用 Web Worker 并行计算和 IndexedDB 缓存,让页面全程丝滑不卡顿。
为什么渲染一张城市海报,浏览器会卡死?
生成一张 300 DPI 的海报,背后有三件"重活":
- 拉数据:从 OpenStreetMap(Overpass API)下载道路、水体、公园、POI,动辄几 MB 的 GeoJSON;
- 算坐标:把每条道路投影成画布坐标,百万级浮点数运算;
- 画图:用 Rust 编译的 WASM 渲染引擎逐像素绘制。
这些任务中任何一件阻塞主线程,界面就会失去响应:按钮点不动、进度条不刷新、动画掉帧。
双 Worker 架构:取数与渲染各占一条线程
MapPoster Online 把"重活"拆给了两个独立的 Web Worker:
| Worker | 文件 | 职责 |
|---|---|---|
| 数据 Worker | src/data-worker.ts | 检查缓存 → 拉取 Overpass 数据 → 压缩存入 IndexedDB |
| 渲染 Worker 池 | src/worker.ts | 加载 WASM 引擎,并行处理道路/水体/公园并渲染 |
主线程只负责"传话":发消息给 Worker、接收结果和进度,自己几乎不做计算。
Worker 池 + 道路分片:把多核 CPU 榨干
一个 Worker 只占一条线程,多核电脑白白浪费。MapPoster Online 的做法是按 CPU 核心数创建 Worker 池(见 src/App.tsx#L1594-L1598):
- 8 核机器 → 开 8 个 Worker;
- 道路数据被
shardRoadsBinary(src/utils.ts#L471)按路段数均匀切成 N 个分片; - 每个 Worker 领一个分片,WASM 引擎同时计算,最后合并成完整道路图层。
水体、公园、POI 则各派给一个 Worker 同步处理(src/App.tsx#L1719-L1729)。8 核机器上,原本串行的计算变成 8 路并行,耗时直接缩短到约 1/N。
三级缓存:第二次生成只要几秒
Overpass API 的响应慢且不稳定,重新拉取数据往往要等几分钟。项目设计了一条"由快到慢"的三级缓存链路(src/services/map-data.ts#L85-L134):
L1 内存缓存 → L2 IndexedDB → L3 网络请求
- L1 内存:
MapDataService内的 JS Map,同一会话内重复生成同一城市,直接命中,毫秒级返回; - L2 IndexedDB:数据 Worker 先把结果 gzip 压缩后写入浏览器的 IndexedDB 数据库(src/db.ts#L20-L33)。下次访问同一城市时,跳过网络,直接解压还原(src/data-worker.ts#L177-L265);
- L3 网络:缓存未命中才请求 Overpass,取到后立刻写回缓存。
缓存键由"国家 + 城市 + 行政区 + 半径 + 精度 + 数据类型"拼成(src/data-worker.ts#L111-L143),保证不同参数各存各的,互不污染。
几个小细节让缓存又快又省空间:
- 用浏览器原生的
CompressionStream做 gzip 压缩,JSON 体积通常缩小 70% 以上; - 只缓存"缺的那几类":roads、water、parks、pois 分别判断命中与否,已缓存的不用重下(src/data-worker.ts#L316-L330);
- 用户关闭 POI 渲染时,直接跳过 POI 的网络请求和缓存检查,省带宽。
零拷贝传输与主线程"让路"
大数组在线程间传来传去也有讲究,两个优化值得抄作业:
- Transferable 零拷贝:
postMessage时把 TypedArray 的 buffer 直接"转移"所有权(src/data-worker.ts#L696-L720)。数据不经过序列化复制,传一个几十 MB 的数组几乎零耗时; - yieldMainThread 让路:主线程在每步之间主动让出执行权(src/App.tsx#L622),让浏览器先完成界面绘制,进度条和文字才能实时刷新,而不是"一顿一顿"。
配合 Worker 里持续回传的PROGRESS消息,界面上的"正在获取道路…等待 API 槽位…"等提示始终是流畅的——这就是用户感知到的"不卡顿"。
小结:普通用户能感受到的好处
- 首次生成:网络等待时间被进度提示填满,界面不掉帧,等待时还能玩内置的贪吃蛇小游戏;
- 再次生成:同一城市 + 同一参数直接走 IndexedDB 缓存,从几分钟压缩到几秒;
- 多核红利:核心数越多,WASM 渲染并行越快。
这套"数据 Worker + 渲染 Worker 池 + 三级缓存 + 零拷贝"的组合,是浏览器端处理重型数据管道的经典范式。想深入源码,可以从这几个入口读起:src/data-worker.ts、src/worker.ts、src/db.ts、src/services/map-data.ts。
【免费下载链接】maptoposter-online
✨❤️🔥Turn the cities you love into stunning designs
相关推荐
页面再也不卡顿!FlexSearch Worker并行索引完全指南(浏览器+Node.js双端实战)
页面再也不卡顿!FlexSearch Worker并行索引完全指南(浏览器+Node.js双端实战) 还在为大数据量索引导致页面卡顿而头疼?FlexSearch
搜索引擎后端airi 实战:VueUse useWebWorkerFn 把昂贵计算搬进 Web Worker,让 AI 伴侣界面永不卡顿
airi 实战:VueUse useWebWorkerFn 把昂贵计算搬进 Web Worker,让 AI 伴侣界面永不卡顿 本指南以 airi 仓库技能目录中
AI 应用大模型AI Agent数字人前端后端桌面应用移动开发音频在 Web Worker 中运行 Pyodide:主线程不卡顿的异步 Python 执行完整指南
在 Web Worker 中运行 Pyodide:主线程不卡顿的异步 Python 执行完整指南 本指南以 Pyodide 官方文档中的 Web Worker
科学计算开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考