有一个应用程序,其中输入类型为“文件”。以下方法获取文件,然后准备好通过AJAX发送到服务器。
private StartUpload = (files) => {
if (files && files.length === 1) {
this.GetFileProperties(files[0])
.done((properties: IFileProperties) => {
$('input[type=file]').val("");
if (this._compatibleTypes.indexOf(properties.Extension) >= 0) {
var base64 = this.ArrayBufferToBase64(properties.ArrayBuffer);
this.DoFileUpload(base64, properties.Extension).always(() => {
this.ShowDialogMessage('edit_document_upload_complete', 'edit_document_upload_complete');
});
} else {
this.ShowDialogMessage('edit_document_upload_incompatible', 'edit_document_upload_compatible_types', this._compatibleTypes);
}
});
} else {
this.ShowDialogMessage('edit_document_upload_one_file', 'edit_document_upload_one_file_msg');
}
};
private ArrayBufferToBase64(buffer): any {
var binary = '';
var bytes = new Uint8Array(buffer);
for (var xx = 0, len = bytes.byteLength; xx < len; xx++) {
binary += String.fromCharCode(bytes[xx]);
}
return window.btoa(binary);
}
private DoFileUpload = (base64, extension) => {
this.IsLoading(true);
var dfd = $.Deferred();
var data = {
data: base64
};
UpdateFormDigest((<any>window)._spPageContextInfo.webServerRelativeUrl, (<any>window)._spFormDigestRefreshInterval);
var methodUrl = "_vti_bin/viewfile/FileInformation.asmx/AddScannedItemAlt";
$.ajax({
headers: {
"X-RequestDigest": $("#__REQUESTDIGEST").val()
},
url: methodUrl,
contentType: "application/json",
data: JSON.stringify(data),
dataType: 'json',
type: "POST",
success: (response) => {
// do stuff
},
error: (e) => {
// do stuff
}
});
return dfd;
};
这绝对适用于绝大多数情况。但是,当文件大小很大(比如200MB +)时,它会杀死浏览器。
Chrome会显示一个带有“aw snap”消息的黑灰色页面,并且基本上已经消失。
IE显示“Out of Memory”控制台错误但仍继续有效。
FF显示“无响应脚本”警告。选择“不再显示我”会让它一直运行,直到出现“内存不足”控制台错误。
这就是死亡的地方:
for (var xx = 0, len = bytes.byteLength; xx < len; xx++) {
binary += String.fromCharCode(bytes[xx]);
}
将try / catch包裹在此处不会产生任何错误,也不会发现任何错误。
我可以在没有崩溃的情况下进入循环,但是因为len = 210164805,所以逐步完成每次迭代都很困难。为此我尝试将console.log(xx)添加到循环并让它飞行 - 但浏览器崩溃之前任何东西都显示在日志中。
字符串的大小是否有限制可能导致浏览器一旦超出就崩溃?
由于
答案 0 :(得分:0)
您需要以异步方式执行此操作,方法是在块或时间段中分解代码。
这意味着你的代码需要使用回调,否则它就是直接的 -
var bytes = new Uint8Array(256*1024*1024); // 256 mb buffer
convert(bytes, function(str) { // invoke the process with a callback defined
alert("Done!");
});
function convert(bytes, callback) {
var binary = "", blockSize = 2*1024*1024, // 2 mb block
block = blockSize, // block segment
xx = 0, len = bytes.byteLength;
(function _loop() {
while(xx < len && --block > 0) { // copy until block segment = 0
binary += String.fromCharCode(bytes[xx++]);
}
if (xx < len) { // more data to copy?
block = blockSize; // reinit new block segment
binary = ""; // for demo to avoid out-of-memory
setTimeout(_loop, 10); // KEY: async wait
// update a progress bar so we can see something going on:
document.querySelector("div").style.width = (xx / len) * 100 + "%";
}
else callback(binary); // if done, invoke callback
})(); // selv-invoke loop
}
html, body {width:100%;margin:0;overflow:hidden}
div {background:#4288F7;height:10px}
<div></div>
使用转换为字符串的大缓冲区可能会使客户端内存不足。转换为字符串的200mb缓冲区将增加2 x 200mb,因为字符串存储为UTF-16(即每个字符2个字节),所以这里我们使用600 mb开箱即用。
这取决于浏览器以及它如何处理内存分配以及系统当然。浏览器将尝试保护计算机免受恶意脚本的攻击,这些脚本会尝试填充内存,例如。
您应该能够留在ArrayBuffer中并将其发送到服务器。