JSON.stringify处理大数据阻塞UI,加载动画停滞问题求助
解决JSON.stringify阻塞UI导致加载动画停滞的问题
核心问题是JSON.stringify在主线程处理大数据时阻塞了UI渲染,要让加载动画持续运行,必须把序列化任务移到非主线程执行,以下是两种可行方案:
方案一:Web Worker(最优解)
Web Worker在后台线程独立运行,完全不占用主线程,能保证加载动画流畅转动。
1. 创建Web Worker文件
新建json.worker.ts,专门处理JSON序列化:
self.onmessage = (event) => { const rawData = event.data; const formattedJson = JSON.stringify(rawData, null, '\t'); self.postMessage(formattedJson); };
2. 修改组件逻辑
调整组件中的变量和方法,改用Worker异步获取序列化结果:
import { ChangeDetectorRef, Component, OnDestroy } from '@angular/core'; @Component({ // 组件元数据 }) export class YourComponent implements OnDestroy { data: any; // 原始数据 jsonView = false; loading = false; jsonResult?: string; // 存储异步序列化后的结果 private jsonWorker: Worker; constructor(private cdr: ChangeDetectorRef) { // 初始化Worker this.jsonWorker = new Worker(new URL('./json.worker', import.meta.url)); // 接收Worker返回的结果 this.jsonWorker.onmessage = (event) => { this.loading = false; this.jsonResult = event.data; this.cdr.markForCheck(); }; } handleJsonViewerOpen() { this.jsonView = true; this.loading = true; this.cdr.markForCheck(); // 立即触发UI更新,显示加载动画 this.jsonWorker.postMessage(this.data); // 给Worker发送待序列化的数据 } ngOnDestroy() { this.jsonWorker.terminate(); // 销毁Worker,避免内存泄漏 } }
3. 更新模板
根据异步状态显示加载动画或JSON结果:
<button id="btnGetJson" pButton icon="fa fa-file-code-o" pTooltip="Json Viewer" tooltipPosition="bottom" class="p-button-secondary" (click)="handleJsonViewerOpen()"></button> <p-dialog [(visible)]="jsonView" header="Json Viewer({{ header }})" positionTop="0" styleClass="custom-dialog" responsive="true" [closable]="false" > <loader [visible]="loading" *ngIf="!jsonResult"></loader> <pre *ngIf="jsonResult" class="json-content">{{ jsonResult }}</pre> </p-dialog>
方案二:拆分序列化任务(应急简易方案)
如果不想引入Web Worker,可以把大任务拆分成小块,用setTimeout让主线程间隙处理UI渲染:
async generateJsonString() { this.loading = true; this.cdr.markForCheck(); const jsonParts: string[] = ['{']; const dataEntries = Object.entries(this.data); for (let i = 0; i < dataEntries.length; i++) { const [key, value] = dataEntries[i]; // 序列化单个键值对 const entryStr = `"${key}": ${JSON.stringify(value)}`; jsonParts.push(entryStr); if (i < dataEntries.length - 1) jsonParts.push(','); // 每处理10个条目就让出主线程,更新UI if (i % 10 === 0) { await new Promise(resolve => setTimeout(resolve, 0)); this.cdr.markForCheck(); } } jsonParts.push('}'); this.jsonResult = jsonParts.join('\n\t'); this.loading = false; this.cdr.markForCheck(); } // 修改打开弹窗的方法 handleJsonViewerOpen() { this.jsonView = true; this.generateJsonString(); }
注意:方案二适合数据结构不太复杂的场景,若数据层级极深,还是Web Worker的效果更稳定。
内容的提问来源于stack exchange,提问作者Askyy
相关产品推荐
相关产品推荐

