24

This is my code.

var xhr = new XMLHttpRequest();
xhr.open('GET',window.location.href, true);
xhr.responseType = "arraybuffer";
xhr.onload = function(event) {
 debugger;
 console.log(" coverting array buffer to string "); 
 alert(String.fromCharCode.apply(null, new Uint8Array(this.response)));
};
xhr.send();

That request is being made to a PDF URL which is around 3 MB in size. I have read a few threads with same error, Maximum call stack size exceeded, telling me that there must be some recursive call but I do not see any recursive call here. Can anyone help?

David Buck
  • 3,752
  • 35
  • 31
  • 35
Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
  • Is this request to the very same page? Using GET on `window.location.href`? – skobaljic Jul 18 '16 at 09:16
  • @skobaljic Yes.For example, the current page is http://www.cs.columbia.edu/~lok/3101/lectures/02-corejava.pdf – Suresh Atta Jul 18 '16 at 09:19
  • If you call same page with same script included, why do you wonder there is too much recursion? Try calling other page with no script. Or if you call via xhr, than do not output the script again, or add parameter to distinct the call. – skobaljic Jul 18 '16 at 10:27
  • @skobaljic this script wont execute in load function. I am just reading the pdf page data. – Suresh Atta Jul 18 '16 at 10:29
  • Have you tried to load other page, other pdf? – skobaljic Jul 18 '16 at 10:30
  • @skobaljic Well, this code is inside extension. When people click an option this code gets execute. If the page is we pure html page, I am using jquery to get body text , where as for pdf url's I can use jquery body text. So reading the contents as arraybuffer and trying to parse it to a string. That is where I am getting this error. – Suresh Atta Jul 18 '16 at 10:37
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/117594/discussion-between-ss--and-skobaljic). – Suresh Atta Jul 18 '16 at 10:57

5 Answers5

30

I had the same problem and I finally used this code:

function _arrayBufferToBase64( buffer ) {
    var binary = '';
    var bytes = new Uint8Array( buffer );
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) {
        binary += String.fromCharCode( bytes[ i ] );
    }
    return window.btoa( binary );
}
Anthony O.
  • 22,041
  • 18
  • 107
  • 163
14

The error is caused by a limitation in the number of function arguments. See "RangeError: Maximum call stack size exceeded" Why?

Instead of String.fromCharCode.apply(), use e. g. a TextEncoder. See Uint8Array to string in Javascript

Community
  • 1
  • 1
le_m
  • 19,302
  • 9
  • 64
  • 74
  • Hi. How do you use the `TextEncoder` in my case? I have this `var base64 = btoa(String.fromCharCode.apply(null, new Uint8Array(blob)));` – Dev Mar 06 '18 at 03:45
  • 2
    I opened a separate [question](https://stackoverflow.com/questions/49123222/converting-array-buffer-to-string-maximum-call-stack-size-exceeded) – Dev Mar 06 '18 at 05:01
  • 1
    For a binary string `TextEncoder` is useless, it does not support `Latin1` (it uses `Windows−1252`), you will get the broken result. `(new TextDecoder("ISO-8859-1").decode(new Uint8Array([148]))).charCodeAt(0);` // 8221, should be 148 – KeyKi Mar 17 '20 at 17:00
6
this.response.arrayBuffer()
              .then((buf) => {
                const uint8Array = new Uint8Array(buf);
                const data = uint8Array.reduce((acc, i) => acc += String.fromCharCode.apply(null, [i]), '');
                return data;
              })
Igor Janenko
  • 61
  • 1
  • 1
1
Thank you so much Anthony O, you saved my 10 days work.
small modification in my scenario is:

Angular 7 :

/** Convert Uint8Array to string */

    private static arrayBufferToBase64( buffer: Uint8Array ) {
        var binary = '';
        var bytes = new Uint8Array( buffer );
        var len = bytes.byteLength;
        for (var i = 0; i < len; i++) {
            binary += String.fromCharCode( bytes[ i ] );
        }
        return  binary;
    }
0

A little bit more optimized variant would be to utilize the available stack size instead of converting each character separately.

var text = '';
for(var i = 0; i < Math.ceil(bytes.length / 32768.0); i++) {
  text += String.fromCharCode.apply(null, bytes.slice(i * 32768, Math.min((i+1) * 32768, bytes.length)))
}
Sven Döring
  • 3,927
  • 2
  • 14
  • 17