- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在构建一个 Web 应用程序,它使用 EvaporateJS 通过分段上传将大文件上传到 Amazon S3。我注意到一个问题,每次启动新 block 时,浏览器都会卡住约 2 秒。我希望用户能够在上传过程中继续使用我的应用程序,这种卡住会带来糟糕的体验。
我使用 Chrome 的时间轴查看导致此问题的原因,发现是 SparkMD5 的散列。因此,我将整个上传过程移到了一个 Worker 中,我认为这可以解决问题。
这个问题现在已在 Edge 和 Firefox 中修复,但 Chrome 仍然存在完全相同的问题。
这是我的时间轴的截图:
如您所见,在卡住期间我的主线程基本上什么都不做,在此期间运行的 JavaScript 不到 8 毫秒。所有工作都发生在我的 Worker 线程中,即使它只运行 ~600 毫秒左右,而不是我的框架所花费的 1386 毫秒。
我真的不确定是什么导致了这个问题,是否有我应该注意的 Workers 陷阱?
这是我的 Worker 的代码:
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 存储桶名称和 AWS 区域、AWS 对象 key 和输入文件对象,这些都在“init”消息中提供。当它需要签名的东西时,它会向父线程发送一条“signingRequest”消息,一旦从我的 API 的签名端点获取它,它就会在“签名”消息中提供签名。
最佳答案
我不能给出一个很好的例子,也不能分析你只用 Worker 代码做什么,但我强烈怀疑这个问题要么与主线程上的 block 读取有关,要么与一些意外处理有关你在主线程上的 block 上做的。也许将调用 postMessage
的主线程代码发布到 Worker?
如果我现在正在调试它,我会尝试将您的 FileReader
操作移到 Worker 中。如果您不介意 Worker 在加载 block 时阻塞,您还可以使用 FileReaderSync
。
生成预签名 URL 是否需要散列文件内容 + 元数据 + key ?散列文件内容将采用 O(n) 的 block 大小,如果散列是从 Blob
读取的第一个操作,则文件内容的加载可能是推迟到散列开始。除非您被迫在主线程中保留签名(您不信任拥有 key Material 的工作人员?)这将是另一件带入工作人员的好事。
如果将签名移动到 Worker 中太多了,您可以让 Worker 做一些事情来强制读取 Blob
和/或传递 ArrayBuffer
(或Uint8Array
或者你有什么)文件内容返回主线程进行签名;这将确保读取 block 不会发生在主线程上。
关于javascript - 工作人员在 Chrome 中阻塞 UI 线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41604594/
是否有用于手动测试的代码覆盖工具?比如我新写了30行代码,编译,然后运行,有什么办法可以快速验证这30行都运行了吗? 另外,后来,在我将代码 checkin 正式版本后,有什么方法可以验证测试部门在进
老实说,这是一个家庭作业问题,但我已经浪费了好几个小时,而且无法正确解决。它返回错误数量的结果或错误的数据: 我需要选择参与指导电影和/或在电影中表演的每个人以及他们所做的次数,如果至少 5 次。 有
我正在尝试测试 MacOS 的应用内购买。输入测试用户凭据后,App Store 提示:“当前收据无效或 ds 人员 ID 不匹配。”并且购买失败。 最佳答案 我尝试了很多方法来解决这个问题。 Get
我正在为 Jenkins 使用 ActiveDirectory 插件,因此用户必须使用他们的凭据登录到 Jenkins。然后用户在 Jenkins 中被称为 joe.doe,这很完美。 当同一个人 c
如何从 Infopath 人员/组选取器检索电子邮件地址?当我将人员/组选取器添加到 infopath 表单时,我只得到 3 个字段 DisplayName、AccountId、AccountType
在 Snow Leopard 中,可以在 iCal 事件中显示空闲/忙碌时间。我搜索了 CalStore.framework 的 header ,但找不到任何描述该字段的属性。如何检索日历事件的忙/闲
是否有人成功地从专门针对 SharePoint 2013 的新建或编辑表单中获取用户(个人或组)字段的值? 我已经尝试了通过搜索互联网找到的所有解决方案以及我自己能想到的所有解决方案,所有结果都为空白
所以我需要将一个 Twitter 帐户添加到 ABRecordRef 中。然而,最快的方法似乎是获取社交资料属性的多值引用,创建它的可变版本,查找它是否有 Twitter 条目,如果已经有,则创建
我正在尝试将使用 Tomcat(最初是 5.5,但可以与 7 一起使用)在 MyEclipse 中开发的应用程序部署到我们的演示服务器 (Sun Java Web Server 7)。不幸的是,所有设
我是一名优秀的程序员,十分优秀!