Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

javascript - locally generating and downloading a huge file

I have the following JavaScript code which downloads a file, which I can't help but think I got from here: Create a file in memory for user to download, not through server

However, this function crashes in Chrome because I'm trying to download too much data (it might be a couple of MB, but it seems to work OK for downloads under 1 MB. I haven't done many metrics on it).

I really like this function because it lets me create a string from an existing huge JavaScript variable and immediately download it.

So my two questions then are:

A) Whats causing the crash? Is it the size of the string text or is there something in this function? I read that 60MB strings were possible in JavaScript and I don't think I'm quite reaching that.

B) If it is this function, is there another simple way to download some huge-ish file that allows me to generate the content locally via JavaScript?

function download(filename, text) {
  var element = document.createElement('a');
  element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
  element.setAttribute('download', filename);

  element.style.display = 'none';
  document.body.appendChild(element);
  element.click();
  document.body.removeChild(element);
}
like image 503
user3475234 Avatar asked Jul 31 '15 17:07

user3475234


2 Answers

Does it work in other browsers? Try using the debugger and set a break point just inside the function and step through.

Try breaking up the element.setAttribute and the data content by creating a var that holds the string you are going to set to href, that way you can see more failure points.

See if the encodeURIComponent function is failing with large strings.

Strings are immutable in javascript, for those who are privy it means that their creation is final, you can't modify the string, or append to one, you have to create a new one for every change. encodeURIComponent which url encodes a string is possibly making thousands of changes escaping a > 1mb string depending on the contents of the string. And even if you are using zero characters that need escaped, when you call that function and then append it to the 'data:text/plain;charset=utf-8,' string, it will create a new string from those two, effective doubling the memory needed for that action.

Depending on how the particular browser is handing this function, its not optimized for long strings at all, since most browsers have a url character limitation of ~2000 characters ( 2048 typically ) then it's likely that the implementation in the browser is not doing a low level escape. If this function is indeed the culprit, you will have to find another way to uri escape your string. possibly a library or custom low level escape.

If the debugger shows that this function is not the issue, the obvious other bottleneck would be when you append this enormous link to the dom, the browser could be freezing there attempting to process this command, and for that it may require a completely different solution to your downloading issue.

Though this is just speculation, hopefully it leads you in the right direction.

like image 100
DiamondDrake Avatar answered Sep 29 '22 05:09

DiamondDrake


While I marked Rickey's answer as the correct one because it got me to the right answer, a workaround I found for this was here:

JavaScript blob filename without link

The accepted answer at this link was capable of handling more than 8MB, while the data URI was capable of handling 2MB, because of Chrome's limit on URI length.

like image 35
user3475234 Avatar answered Sep 29 '22 05:09

user3475234