9

There must be a way to do this more efficiently. What I'm doing is conceptually very simple:

1) Call a web service and receive b64-encoded-string of a PDF blob.
2) Decode it, create blob, render PDF in new window. Account for pop-up blocker.

My code works. Nothing fancy. Its all client-side. Everything works but IE runs SUPER slow compared to the other browsers (IE 11 vs. current Chrome/Firefox/Safari).

In light of this I am certain I could do this more efficiently. Any tips on how to speed this up for IE 11?

Note: I'm using Jeremy's b64toBlob function (thanks Jeremy).

Part I: modal stuff

var box = new SimpleDialog(Dialogs.getNextId(), false); 
box.title = "Fetching PDF"; 
box.isMovable = false; 
box.extraClass = ""; 
box.width = 400; 
box.isModal = true; 
box.createDialog(); 
window.parent.box = box; 
box.setContentInnerHTML('<p>Please wait....</p>'); 
box.show(); 

Part II: call external service, receive b64 encoded string

setTimeout(function(){ 
  var response = ... ; //do callout... get data
  var statusCode = ...; //parse from response 
  var b64Data = ... ; //parse from response

  if(statusCode == 200) { 
    //Account for IE
    if (navigator.appVersion.toString().indexOf('.NET') > 0) { 
      var blob = b64toBlob(b64Data, "application/pdf"); 
      var fileURL = URL.createObjectURL(blob); 
      window.navigator.msSaveOrOpenBlob(blob, "theFile.pdf"); 
      window.parent.box.cancel(); 
    } else {
      var blob = b64toBlob(b64Data, "application/pdf"); 
      var fileURL = URL.createObjectURL(blob); 
      var pdfWin = window.open(fileURL,"_blank","width=1000,height=800"); 
      if(!pdfWin) { 
        box.setTitle("Success: PDF has been retrieved"); 
        box.setContentInnerHTML("<p align='left'></p><p align='left'>A popup blocker was detected. The PDF will not open automatically.<br /><br /></p><p align='left'><a onclick='window.parent.box.cancel();' target='_blank' href='"+fileURL +"' >Click here to view .pdf</a><br /><br /></p><p align='center'><button class='btn' onclick='window.parent.box.cancel(); return false;'>Cancel</button></p>"); 
      } else { 
        window.parent.box.cancel(); 
      } 
    } 

  } else { 
      box.setTitle("Error fetching PDF"); 
      box.setContentInnerHTML("<p align='left'><img src='/img/msg_icons/warning32.png' style='margin:0 5px;'/></p><p align='left'>Unable to retrieve PDF.</p><p align='center'><button class='btn' onclick='window.parent.box.cancel(); return false;'>OK</button></p>"); 
  } 
},200);
Community
  • 1
  • 1
krigi
  • 143
  • 7
  • If I had to guess I would say that the reason IE takes so long is because the msSaveOrOpenBlob method has to save the file locally. – QuestionMarks Aug 19 '16 at 12:53
  • hmm. are you saying that msSaveOrOpenBlob saves local even before it renders its save-or-open dialogue? – krigi Aug 19 '16 at 22:36
  • 1
    Have you considered using webworkers? If you don't need to support versions < IE 11 that could be an option. – user2977636 Aug 22 '16 at 22:02

1 Answers1

3

I don't really see any slowness, and this plunkr run in IE, (using an update on the original "Jeremy" solution) works just fine:

Sample pdf

There was an update in the original post that improves the answer further:

function base64toBlob(base64Data, contentType, sliceSize) {

    var byteCharacters,
        byteArray,
        byteNumbers,
        blobData,
        blob;

    contentType = contentType || '';

    byteCharacters = atob(base64Data);

    // Get blob data sliced or not
    blobData = sliceSize ? getBlobDataSliced() : getBlobDataAtOnce();

    blob = new Blob(blobData, { type: contentType });

    return blob;


    /*
     * Get blob data in one slice.
     * => Fast in IE on new Blob(...)
     */
    function getBlobDataAtOnce() {
        byteNumbers = new Array(byteCharacters.length);

        for (var i = 0; i < byteCharacters.length; i++) {
            byteNumbers[i] = byteCharacters.charCodeAt(i);
        }

        byteArray = new Uint8Array(byteNumbers);

        return [byteArray];
    }

    /*
     * Get blob data in multiple slices.
     * => Slow in IE on new Blob(...)
     */
    function getBlobDataSliced() {

        var slice,
            byteArrays = [];

        for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
            slice = byteCharacters.slice(offset, offset + sliceSize);

            byteNumbers = new Array(slice.length);

            for (var i = 0; i < slice.length; i++) {
                byteNumbers[i] = slice.charCodeAt(i);
            }

            byteArray = new Uint8Array(byteNumbers);

            // Add slice
            byteArrays.push(byteArray);
        }

        return byteArrays;
    }
}

From the answer here:

martinoss answer

Is the plunkr slow for you? Can you put in some logging to understand which call is actually slow? Put in a timer and log each line. on the IE route. Which one is reporting "slowness"?

Update On the plunkr, I've put a very simple timer, it shows that there is just 46ms approx taken to get the PDF to you in IE11. Obviously it's not multithreaded, but it is an indication.

Community
  • 1
  • 1
PeterS
  • 2,818
  • 23
  • 36
  • thanks for pointing out the revised "one slice" getBlobDataAtOnce() method. That will shave some time off for sure. – krigi Aug 25 '16 at 16:33