发布
社区首页 >问答首页 >下载大型IE11文件时挂起

下载大型IE11文件时挂起
EN

Stack Overflow用户
提问于 2017-09-08 11:29:04
回答 1查看 1.4K关注 0票数 1

对于此代码中的IE11,base64文件被转换为Blob,然后创建一个下载链接。但是,对于一个大型base64文件(~ >5Mb),在创建Blob时浏览器会挂起:

代码语言:javascript
代码运行次数:0
复制
new Blob(byteArrays, {type: contentType});

如何才能解决这个问题呢?

代码语言:javascript
代码运行次数:0
复制
var fullFileName = 'example.test';
var b64file = '';
var contentType = 'application/octet-stream';

b64toBlob(b64file, contentType, 512, function(blob){
  if (typeof MouseEvent != "function") {  //for IE
    $('#ie_download').off('click').on('click', function(){
      window.navigator.msSaveBlob(blob, fullFileName);
    })
      .show();
    success();
    return;
  }
  //other browsers
  var blobUrl = URL.createObjectURL(blob);
  var jqLink = $('<a style="display: none" target="_blank">Save</a>');
  $('#download')
    .attr('download', fullFileName)
    .attr('href', blobUrl)
    .show();
  success();
});

function success () {
  $('#waiting').hide();
}

function b64toBlob(b64Data, contentType, sliceSize, resultCb) {
  contentType = contentType || '';
  sliceSize = sliceSize || 512;

  var byteCharacters = atob(b64Data);
  var byteArrays = [];

  var offset = 0;
  setTimeout(function generateByteArrays () {
    var slice = byteCharacters.slice(offset, offset + sliceSize);
    var byteNumbers = new Array(slice.length);
    for (var i = 0; i < slice.length; i++) {
      byteNumbers[i] = slice.charCodeAt(i);
    }
    var byteArray = new Uint8Array(byteNumbers);
    byteArrays.push(byteArray);

    offset += sliceSize;
    if (offset < byteCharacters.length) {
      setTimeout(generateByteArrays, 0);
    }
    else {
      resultCb(new Blob(byteArrays, {type: contentType}));
    }
  }, 0);
}
代码语言:javascript
代码运行次数:0
复制
#download, #ie_download {
  display: none;
}
代码语言:javascript
代码运行次数:0
复制
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='waiting'>waiting...</div>
<a id='download'>Save</a>
<a id='ie_download'>IE Save</a>

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-09-08 17:15:32

更新

我刚刚注意到,段大小为512个字节。这是非常小的,并将与一个5 mb文件创建10,240数组片,IE似乎做了一个非常缓慢的操作(即。创建缓冲区、复制内容、检查下一片、创建旧大小和下一片大小的新缓冲区、复制旧缓冲区+新内容等等)。

您应该能够使用至少1000 x更大的片大小(0.5mb),并且不阻塞IE11。

使用具有较大切片大小的原始代码进行演示:

代码语言:javascript
代码运行次数:0
复制
setTimeout(test, 10);

function test() {
  // Generate a big base-64 string, chop off data-uri
  // NOTE: Initial creation will take a couple of seconds...
  var c = document.createElement("canvas"); c.width = c.height = 6000;
  var ctx = c.getContext("2d"); // create some lines to degrade compression ratio...
  for(var i = 0, r = Math.random.bind(Math), w = c.width, h = c.height; i < 500; i++) {
    ctx.moveTo(r()*w, r()*h);ctx.lineTo(r()*w, r()*h);
  }
  ctx.stroke();
  var base64 = c.toDataURL();
  base64 = base64.substr(base64.indexOf(",")+1);

  // OK, now we have a raw base64 string we can use to test
  document.querySelector("out").innerHTML = "Converting...";

  // Increase sliceSize by x1024
  b64toBlob(base64, "application/octet-stream", 512<<10, function(blob) {
    document.querySelector("out").innerHTML = "Blob size: " + blob.size;
  });

  function b64toBlob(b64Data, contentType, sliceSize, resultCb) {
    contentType = contentType || '';
    sliceSize = sliceSize || (512<<10);

    var byteCharacters = atob(b64Data);
    var byteArrays = [];

    var offset = 0;
    setTimeout(function generateByteArrays () {
      var slice = byteCharacters.slice(offset, offset + sliceSize);
      var byteNumbers = new Array(slice.length);
      for (var i = 0; i < slice.length; i++) {
        byteNumbers[i] = slice.charCodeAt(i);
      }
      var byteArray = new Uint8Array(byteNumbers);
      byteArrays.push(byteArray);

      offset += sliceSize;
      if (offset < byteCharacters.length) {
        setTimeout(generateByteArrays, 5);
      }
      else {
        resultCb(new Blob(byteArrays, {type: contentType}));
      }
    }, 5);
  }
}
代码语言:javascript
代码运行次数:0
复制
<out>Creating test data...</out>

由于错误 in IE11,所以不能将XMLHttpRequest()与数据-uri和响应类型"blob“一起使用,否则您可以使用它为您执行所有这些操作。

代码语言:javascript
代码运行次数:0
复制
var c = document.createElement("canvas"); c.width = c.height = 4000;
var ctx = c.getContext("2d"); // create some lines to degrade compression ratio...
for(var i = 0, r = Math.random.bind(Math), w = c.width, h = c.height; i < 200; i++) {
  ctx.moveTo(r()*w, r()*h);ctx.lineTo(r()*w, r()*h);
}
ctx.stroke();
var base64 = c.toDataURL();
base64 = base64.substr(base64.indexOf(",")+1);

b64toBlob(base64, "application/octet-stream", function(blob) {
  console.log(blob)
})

// Using XMLHttpRequest to do the work (won't work in IE11...)
function b64toBlob(base64, mimeType, callback) {
  var xhr = new XMLHttpRequest();
  xhr.responseType = "blob";
  xhr.onload = function() {
    callback(this.response)
  };
  xhr.open("GET", "data:" + mimeType + ";base64," + base64);
  xhr.send();
}

旧答案(仍然适用/推荐)

将超时时间增加到7-10ms,看看是否解除了循环的阻塞(如果仍然阻塞,则使用更高的值)。

超时值为0实际上超出了这种异步分段方法的目的。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46115477

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档