文件下载引发的网页崩溃

最近实现了个异步下载文件的功能,Chrome下只要触发一定大小比如200MB的文件下载,浏览器网页会崩掉,其它网页浏览器却是OK的。查看控制台也并没有任何报错。 同样操作测试Safari/Firefox是OK的,仅有Chrome有此问题。该问题最终解决,这里mark下。

报错信息

说明:

  • 开发者工具-控制台无其它报错信息。
  • 网页报错信息为Error code:RESULT_CODE_KILLED_BAD_MESSAGE

https://static.1991421.cn/2022/2022-12-25-234224.jpeg

相关下载逻辑代码如下

1
2
3
4
5
6
7
8
9
10
11
function downloadFile(packets) {
const blob = new Blob(packets, {
type: 'application/octet-stream',
});
const downloadLink = document.createElement('a');
document.body.appendChild(downloadLink);
downloadLink.href = URL.createObjectURL(blob);
downloadLink.target = '_self';
downloadLink.download = 'empty.txt';
downloadLink.click();
}

除了不同浏览器表现行为不一致外,还有一个现象是,因为下载这里我们有两种API,所以效果是A可以,B不可以,对比发现两者的唯一区别是分片二进制数据大小不一致,一个是3KB,一个是100KB。

分析

由于刚好有一种API下载是可以的,而区别仅仅是分片大小,因此问题直接定位到了,即分片大小过小导致200MB数据创建内存数组长度过大,因此网页崩溃。至于其它浏览器没有崩溃也好理解,即不同浏览器对此限制不同。

解决

对此,简单将3KB的分片大小调节为100KB即可。但假如之后文件大小增大,这样的问题还是会出现,因此需要根治解决。

根治的办法有2种

  1. 是直接流化保存,JS也有Stream支持,可以流化保存就不用耗费大内存,尤其是大文件
  2. 很多大文件下载是暴露URL,交付给了浏览器下载,这里blob算是网页自己管理了下载的过程,所以内存开销绕不开,尤其大文件出问题。

延伸

比如chrome,单个页签内存有限,比如网页中用一个参数保存300-500MB的数据,网页也是会崩溃,因此内存使用还是需要谨慎。针对下载,尤其是大数据量,还是优先使用同步下载方案。