对于此代码中的IE11,base64文件将转换为Blob,然后创建下载链接。但是使用大型base64文件(〜> 5Mb),浏览器会在创建Blob时挂起:
new Blob(byteArrays, {type: contentType});
如何解决这个问题?
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);
}
#download, #ie_download {
display: none;
}
<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>
答案 0 :(得分:3)
<强>更新强>
我刚注意到段大小为512 bytes 。这非常小,并且将使用5 MB文件创建10,240个数组切片,IE似乎执行非常慢的操作(即创建缓冲区,复制内容,检查下一个切片,创建旧大小的新缓冲区和下一个切片的大小,复制旧缓冲区+新内容等。)。
你应该能够使用至少1000倍的切片大小(0.5 mb)并且不会阻止IE11。
使用较大切片大小的原始代码进行演示:
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);
}
}
<out>Creating test data...</out>
由于IE11中的bug,不能将XMLHttpRequest()
与data-uri和响应类型“blob”一起使用,否则您可以使用它来为您执行所有这些操作。
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实际上超出了此异步分段方法的目的。