javascript - 异步上传多个文件时浏览器/服务器挂起?
问题描述
可能有一个简单的答案,但我不知道:
问题是我正在通过 XMLHttpRequests 上传多个文件,并从 for 循环中调用它。这会遍历必须上传的文件(使用 webkitdirectory 的整个文件夹)。如果我没有大量文件,那部分所有文件都可以工作,但我可能有多达 300 个或可能,可能永远不会超过 1000 个。我从 Github 项目中获得了原始代码:
UploadFolder,但我已经对其进行了一些编辑以满足我的需要。我认为关键代码仍然基本相同。
经过一些预处理后,有一个循环遍历要上传的文件列表并调用函数将文件上传到服务器:
for (var i = 0; i < picker.files.length; i++) {
var file = picker.files[i];
if (processflag[i] == false) {
let lineitem = statusitem(file, "Skipped (.hidden file)");
listing.insertAdjacentHTML('beforeend', lineitem);
}
else {
sendFile(file);
}
}
sendfile 函数很长,所以我只包含了可能是关键部分的内容:
sendFile = function(file) {
var timestamp = picker.dataset.timestamp;
var formData = new FormData();
// Set post variables
requestcounter = requestcounter + 1;
formData.set('timestamp', timestamp);
formData.set('counter', requestcounter);
formData.set('total', total);
formData.set('webkitpath', file.webkitRelativePath);
formData.set('file', file); // One object file
var request = new XMLHttpRequest();
request.responseType = 'json';
// HTTP onload handler
request.onload = function() {
if (request.readyState === request.DONE) {
if (request.status === 200) {
console.log(request.response);
// Does a bunch of post-processing stuff here
// .....
// .........
}
else {
// issue with request
}
}
}
// Do request
request.open("POST", '/OrthancDev/UploadFolder');
request.send(formData);
}
HTML 不是那么重要。
<div class="picker">
<input type="file" id="picker" name="fileList" webkitdirectory multiple data-timestamp = "">
</div>
可能是最相关的部分,时间戳是动态设置的。
在服务器端,使用 PHP 对 POST 进行了一些相当复杂的处理,并且还执行了一些安装二进制文件,例如:
$proc = proc_open(path_to_executable',[
1 => ['pipe','w'],
2 => ['pipe','w'],
],$pipes);
$stdout = stream_get_contents($pipes[1]);
fclose($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
proc_close($proc);
. . . .
并将上传移动到服务器上的文件夹:
move_uploaded_file($file_tmp, $upload_path);
到服务器的 POST 包括:
-----------------------------19160542578905591423661131170
Content-Disposition: form-data; name="timestamp"
2020-05-09-15-44-36
-----------------------------19160542578905591423661131170
Content-Disposition: form-data; name="counter"
24
-----------------------------19160542578905591423661131170
Content-Disposition: form-data; name="total"
25
-----------------------------19160542578905591423661131170
Content-Disposition: form-data; name="webkitpath"
POST_T1_FS_TSE_SAG_2MM_12001/IM-0009-0025.dcm
-----------------------------19160542578905591423661131170
Content-Disposition: form-data; name="file"; filename="POST_T1_FS_TSE_SAG_2MM_12001/IM-0009-0025.dcm"
Content-Type: application/dicom
顺便说一句,上传的文件是否也会转到服务器上的 /tmp 目录?
问题是,对于一小部分文件,比如 8 个左右,一切似乎都可以正常工作,但是对于大量文件(例如,甚至只有 25 个),浏览器或服务器“挂起”。我正在使用 Apache 在 MAMP 服务器上运行所有内容,Apache 日志看起来很好,PHP 日志也是如此,我在那里没有看到任何错误。
它确实会快速连续地发送大量 AJAX 请求。
我不熟悉 FF 开发工具中的“计时选项卡”,但在发出最后一个请求时,“阻塞”时间显示为 1.38 秒。看起来所有文件都已上传到服务器,但浏览器此后对该虚拟主机无响应。
我认为这可能与连续触发那么多异步请求有关。我可以尝试同步发出这些请求,看看是否需要太长时间,或者使用某种承诺,或者限制活动异步请求的数量,但我不知道该怎么做。
我不确定这是否也是服务器端问题。单个文件大约 1MB,但可能更大,整个文件夹大约 256 MB,但也可能更大。
这显然是服务器端问题。有一个进程运行似乎挂起服务器的可执行文件,从而挂起浏览器:
$proc = proc_open($exec,[
1 => ['pipe','w'],
2 => ['pipe','w'],
],$pipes);
. . . .
从命令行运行大约需要 30 秒,但看起来所有文件都被发送到服务器并保存,所以看起来最后一个进程导致了问题。
CLI 的输出是:
XMIT: .........................................................................
I: Received Store Response (Success)
I: Sending file: /Users/sscotti/Desktop/newtelerad2/dicomtemp/DEV01/2020-05-10-05-44-14/UC5457343/T1_TSE_SAGITTAL_2MM_6001/IM-0003-0021.dcm
I: Converting transfer syntax: Little Endian Explicit -> Little Endian Explicit
I: Sending Store Request (MsgID 18, MR)
但大约 300 倍,每个文件 1 个。如果有一种很好的方法来解析来自 STDOUT 的输出(例如 I、W、E),那就太好了
解决方案
推荐阅读
- android - 如何仅在一个片段中显示来自工具栏的 SearchView?
- mysql - mysql和mysqlsh/mysqlshell之间查询执行/加载的区别
- python - Discord.py 获取所有公会机器人的名称在 1 个嵌入/消息中
- c - 有时使用 localtime() 函数会出现错误的时间
- android - Flutter 为 Android 和 IOS 设计不同的设计
- python - 如果文件已关闭,为什么我会收到 PermissionError?(Python)
- sql - Power BI - 使用 Dax 根据 Group By 进行筛选
- json - 如何在 Superset 中格式化图表?
- function - Google 表格 - 将多个 IF 函数合并到一个单元格中
- sas - 在 SAS 中创建组合