safari加载大json卡死是因json.parse同步阻塞主线程;应优先用fetch().then(r => r.json())流式解析(需safari≥16.4),次选手动流式分块解析或web worker异步解析。

当Safari加载几十MB以上的JSON数据时,页面会完全卡死、无法滚动、点击无反应,甚至触发“网页无响应”警告框——这不是网络慢,而是JavaScript主线程被同步解析操作彻底锁死。
确认是否为JSON.parse阻塞导致
打开Safari开发者工具(Cmd+Opt+I),切换到Console标签页,粘贴执行:console.time("parse"); JSON.parse('{"a":1}'); console.timeEnd("parse")。如果耗时在0.1ms以内,说明基础解析正常;若超过50ms或直接报错,问题出在你实际处理的JSON字符串上。
在Network面板中找到对应接口 → 点击 → 切换到Response选项卡 → 点击右上角“Copy response”复制原始响应体。注意:不要复制Preview里的美化后内容,必须用Response原始文本。
用流式解析替代一次性JSON.parse
方法一:使用Safari原生支持的response.json()配合fetch中断检测
将原本的fetch(url).then(r => r.text()).then(text => JSON.parse(text))改为:
fetch(url).then(r => {<br> if (!r.ok) throw new Error(r.status);<br> return r.json(); // Safari 16.4+已支持,自动流式解析并分块释放内存<br>})
此方式由WebKit底层接管解析流程,避免主线程长时间占用。【必须确保Safari版本≥16.4,低于此版本会退化为同步解析】
方法二:手动分块解析超大JSON数组(适用于JSON根节点为数组)
第一步:用response.body.getReader()读取流,逐段提取以[、]或,为边界的JSON片段;
详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
第二步:对每个合法对象片段调用JSON.parse(chunk)并立即处理(如存入IndexedDB或渲染首屏);
第三步:用AbortController监听用户离开页面动作,主动中断读取——这能防止后台继续消耗CPU。
注意:该方案不适用于根节点为对象的JSON,且需自行处理嵌套括号匹配,开发成本高,仅推荐数据结构固定、后端可配合改造的场景。
强制降级为Web Worker解析
创建json-parser.worker.js文件,内容为:
self.onmessage = async ({ data }) => {<br> try {<br> const result = JSON.parse(data);<br> self.postMessage({ type: 'success', payload: result });<br> } catch (e) {<br> self.postMessage({ type: 'error', message: e.message });<br> }<br>};
主页面中:
const worker = new Worker('json-parser.worker.js');<br>worker.postMessage(largeJsonString);<br>worker.onmessage = ({ data }) => {<br> if (data.type === 'success') render(data.payload);<br>};
【此方案要求largeJsonString必须是字符串类型,不能是Blob或ArrayBuffer;若原始数据来自fetch,需先调用response.text()获取字符串】
这一步完成后,页面恢复响应,用户可正常滚动、点击,解析结果通过postMessage异步返回。










