[英]Worker blocking UI thread in Chrome
我正在构建一个使用EvaporateJS的Web应用程序,使用Multipart上传将大文件上传到Amazon S3。 我注意到一个问题,每次启动新块时,浏览器都会冻结约2秒钟。 我希望用户能够在上传过程中继续使用我的应用程序,这种冻结会让人感觉不舒服。
我使用Chrome的时间轴来查看造成这种情况的原因,发现它是SparkMD5的散列。 所以我把整个上传过程转移到了一个工作者,我认为这会解决问题。
那么问题现在已经在Edge和Firefox中得到修复,但Chrome仍然存在完全相同的问题。
这是我的时间轴的截图:
正如你所看到的,在冻结期间,我的主线程基本上什么也没做,在此期间运行<8ms的JavaScript。 所有工作都在我的工作线程中进行,即使只运行约600ms左右,而不是我的框架所需的1386ms。
我真的不确定是什么导致了这个问题,是否有任何与工人有关的问题我应该注意什么?
这是我的工人的代码:
var window = self; // For Worker-unaware scripts
// Shim to make Evaporate work in a Worker
var document = {
createElement: function() {
var href = undefined;
var elm = {
set href(url) {
var obj = new URL(url);
elm.protocol = obj.protocol;
elm.hostname = obj.hostname;
elm.pathname = obj.pathname;
elm.port = obj.port;
elm.search = obj.search;
elm.hash = obj.hash;
elm.host = obj.host;
href = url;
},
get href() {
return href;
},
protocol: undefined,
hostname: undefined,
pathname: undefined,
port: undefined,
search: undefined,
hash: undefined,
host: undefined
};
return elm;
}
};
importScripts("/lib/sha256/sha256.min.js");
importScripts("/lib/spark-md5/spark-md5.min.js");
importScripts("/lib/url-parse/url-parse.js");
importScripts("/lib/xmldom/xmldom.js");
importScripts("/lib/evaporate/evaporate.js");
DOMParser = self.xmldom.DOMParser;
var defaultConfig = {
computeContentMd5: true,
cryptoMd5Method: function (data) { return btoa(SparkMD5.ArrayBuffer.hash(data, true)); },
cryptoHexEncodedHash256: sha256,
awsSignatureVersion: "4",
awsRegion: undefined,
aws_url: "https://s3-ap-southeast-2.amazonaws.com",
aws_key: undefined,
customAuthMethod: function(signParams, signHeaders, stringToSign, timestamp, awsRequest) {
return new Promise(function(resolve, reject) {
var signingRequestId = currentSigningRequestId++;
postMessage(["signingRequest", signingRequestId, signParams.videoId, timestamp, awsRequest.signer.canonicalRequest()]);
queuedSigningRequests[signingRequestId] = function(signature) {
queuedSigningRequests[signingRequestId] = undefined;
if(signature) {
resolve(signature);
} else {
reject();
}
}
});
},
//logging: false,
bucket: undefined,
allowS3ExistenceOptimization: false,
maxConcurrentParts: 5
}
var currentSigningRequestId = 0;
var queuedSigningRequests = [];
var e = undefined;
var filekey = undefined;
onmessage = function(e) {
var messageType = e.data[0];
switch(messageType) {
case "init":
var globalConfig = {};
for(var k in defaultConfig) {
globalConfig[k] = defaultConfig[k];
}
for(var k in e.data[1]) {
globalConfig[k] = e.data[1][k];
}
var uploadConfig = e.data[2];
Evaporate.create(globalConfig).then(function(evaporate) {
var e = evaporate;
filekey = globalConfig.bucket + "/" + uploadConfig.name;
uploadConfig.progress = function(p, stats) {
postMessage(["progress", p, stats]);
};
uploadConfig.complete = function(xhr, awsObjectKey, stats) {
postMessage(["complete", xhr, awsObjectKey, stats]);
}
uploadConfig.info = function(msg) {
postMessage(["info", msg]);
}
uploadConfig.warn = function(msg) {
postMessage(["warn", msg]);
}
uploadConfig.error = function(msg) {
postMessage(["error", msg]);
}
e.add(uploadConfig);
});
break;
case "pause":
e.pause(filekey);
break;
case "resume":
e.resume(filekey);
break;
case "cancel":
e.cancel(filekey);
break;
case "signature":
var signingRequestId = e.data[1];
var signature = e.data[2];
queuedSigningRequests[signingRequestId](signature);
break;
}
}
请注意,它依赖于调用线程为其提供AWS公钥,AWS Bucket Name和AWS区域,AWS Object Key和输入File对象,这些都在“init”消息中提供。 当需要签名时,它会向父线程发送'signingRequest'消息,一旦从我的API签名端点获取签名,就会在签名中提供签名。
我不能给出一个很好的例子或分析你正在用的只有Worker代码做什么,但我强烈怀疑这个问题要么与主线程上的块读取有关,要么与你的一些意外处理有关。做主线程上的块。 也许发布调用postMessage
的主线程代码给Worker?
如果我现在正在调试它,我会尝试将FileReader
操作移动到Worker中。 如果您在加载块时不介意Worker阻塞,您还可以使用FileReaderSync
。
生成预签名URL是否需要散列文件内容+元数据+密钥? 散列文件内容将占用块大小的O(n),如果散列是从Blob
读取的第一个操作,则可能延迟加载文件内容直到散列开始。 除非你被迫在主线程中保持签名(你不相信那些拥有关键材料的工人?),这将是另一件带给工人的好事。
如果将签名移入Worker中的过多,您可以让工作人员做一些事情来强制读取Blob
和/或将文件内容的ArrayBuffer
(或Uint8Array
或者你有什么)传回主线程进行签名; 这将确保在主线程上不会发生读取块。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.