Я пытаюсь загрузить файлы через веб-форму на сервер Google Диска с помощью функции возобновляемой загрузки. Я начинаю со скрипта из https://github.com/tanaikech/AsynchronousResumableUploadForGoogleDrive/
Я потратил на это много времени, но безуспешно. Я хотел бы загрузить 1000 файлов. Сейчас асинхронный скрипт работает так, что все 1000 будут загружаться одновременно. Я хотел бы загрузить (например) 10 файлов одновременно, затем повторить для следующих 10 и так далее, пока не закончите. Я считаю, что моя проблема в том, что мне нужно будет изменить https://cdn.jsdelivr.net/gh/tanaikech/ResumableUploadForGoogleDrive_js@master/resumableupload_js.min.js
(включено в index.html
). Я уже разделил files
на части по 10, но при выполнении chunk.forEach...
асинхронная природа https://cdn.jsdelivr.net/gh/tanaikech/ResumableUploadForGoogleDrive_js@master/resumableupload_js.min.js
по-прежнему загружает их все параллельно.
На чем мне следует сосредоточиться, чтобы ограничить только 10 асинхронных ответов и дождаться завершения, а затем повторить?
Для воспроизведения используйте инструкции по настройке в README.md из репозитория, ссылку на который я дал выше. Кроме того, используйте код ниже для index.html
.
Обратите внимание, что для того, чтобы это работало, <insert folder ID>
в файле index.html
ниже необходимо обновить до вашего собственного идентификатора папки.
<input type = "file" id = "file" multiple = "true" />
<input type = "button" onclick = "run()" value = "Upload" />
<div id = "progress"></div>
<script>src = "https://cdn.jsdelivr.net/gh/tanaikech/ResumableUploadForGoogleDrive_js@master/resumableupload_js.min.js"</script>
<script>
function run() {
google.script.run.withSuccessHandler(accessToken => ResumableUploadForGoogleDrive(accessToken)).getAuth();
}
function ResumableUploadForGoogleDrive(accessToken) {
const f = document.getElementById("file");
const chunkSize = 10;
const totalChunks = Math.ceil(f.files.length / chunkSize);
console.info("The totalChunks are: " + totalChunks);
for (let i = 0; i < totalChunks; i++) {
const startIndex = i * chunkSize;
console.info("The startIndex is: " + startIndex);
const endIndex = startIndex + chunkSize;
console.info("The endIndex is: " + endIndex);
const chunk = Array.from(f.files).slice(startIndex, endIndex);
console.info("The chunk is: " + chunk);
chunk.forEach((file, i) => {
if (!file) return;
let fr = new FileReader();
fr.fileName = file.name;
fr.fileSize = file.size;
fr.fileType = file.type;
fr.readAsArrayBuffer(file);
fr.onload = e => {
var id = "p" + ++i;
var div = document.createElement("div");
div.id = id;
document.getElementById("progress").appendChild(div);
document.getElementById(id).innerHTML = "Initializing.";
const f = e.target;
const resource = { fileName: fr.fileName, fileSize: fr.fileSize, fileType: fr.fileType, fileBuffer: fr.result, accessToken: accessToken, folderId: "<insert folder ID>" };
const ru = new ResumableUploadToGoogleDrive();
ru.Do(resource, function (res, err) {
if (err) {
console.info(err);
return;
}
console.info(res);
let msg = "";
if (res.status == "Uploading") {
msg = Math.round((res.progressNumber.current / res.progressNumber.end) * 100) + "% (" + fr.fileName + ")";
} else {
msg = res.status + " (" + fr.fileName + ")";
}
document.getElementById(id).innerText = msg;
});
};
});
};
};
</script>
Обновлено воспроизводимым примером кода.
В вашей ситуации как насчет следующего примера сценария?
Прежде чем использовать этот скрипт, включите Drive API в расширенных службах Google.
code.gs
function getAuth() {
// DriveApp.createFile(blob) // This is used for adding the scope of "https://www.googleapis.com/auth/drive".
return ScriptApp.getOAuthToken();
}
function showSidebar() {
var html = HtmlService.createHtmlOutputFromFile("index");
SpreadsheetApp.getUi().showSidebar(html);
}
index.html
Пожалуйста, измените идентификатор папки на folderId: "root",
.
<input type = "file" id = "file" multiple = "true" />
<input type = "button" onclick = "run()" value = "Upload" />
<div id = "progress"></div>
<script src = "https://cdn.jsdelivr.net/gh/tanaikech/[email protected]/resumableupload_js.min.js"></script>
</script>
<script>
function run() {
google.script.run.withSuccessHandler(accessToken => ResumableUploadForGoogleDrive(accessToken)).getAuth();
}
function upload({ accessToken, file, idx }) {
return new Promise((resolve, reject) => {
let fr = new FileReader();
fr.fileName = file.name;
fr.fileSize = file.size;
fr.fileType = file.type;
fr.readAsArrayBuffer(file);
fr.onload = e => {
var id = `p_${idx}`;
var div = document.createElement("div");
div.id = id;
document.getElementById("progress").appendChild(div);
document.getElementById(id).innerHTML = "Initializing.";
const f = e.target;
const resource = {
fileName: f.fileName,
fileSize: f.fileSize,
fileType: f.fileType,
fileBuffer: f.result,
accessToken: accessToken,
folderId: "root",
};
const ru = new ResumableUploadToGoogleDrive();
ru.Do(resource, function (res, err) {
if (err) {
reject(err);
return;
}
console.info(res);
let msg = "";
if (res.status == "Uploading") {
msg = Math.round((res.progressNumber.current / res.progressNumber.end) * 100) + `% (${f.fileName})`;
} else {
msg = `${res.status} (${f.fileName})`;
}
if (res.status == "Done") {
resolve(res.result);
}
document.getElementById(id).innerText = msg;
});
};
});
}
async function ResumableUploadForGoogleDrive(accessToken) {
const n = 10; // You can adjust the chunk size.
const f = document.getElementById("file");
const files = [...f.files];
const splitFiles = [...Array(Math.ceil(files.length / n))].map((_) => files.splice(0, n));
for (let i = 0; i < splitFiles.length; i++) {
const res = await Promise.all(splitFiles[i].map(async (file, j) => await upload({ accessToken, file, idx: `${i}_${j}` })));
console.info(res);
}
}
</script>
При запуске этого сценария получается следующий результат. В данном случае используется const n = 2;
. Таким образом, файлы загружаются каждые два файла с помощью асинхронного процесса.
Огромное спасибо, @Tanaike! Я так много использовал ваш код и очень признателен за все, что вы внесли в ответ. Я был слишком сосредоточен на вашем репозитории AsynchronousResumableUploadForGoogleDrive и не особо заглядывал в ResumableUploadForGoogleDrive_js в поисках образцов. Могу ли я предложить добавить эти образцы Async также в первый репозиторий? Тем не менее, это решило проблему! :)
@Dan Спасибо за ответ и тестирование. Я рад, что ваша проблема была решена. Спасибо и вам. Насчет Might I suggest to add those Async samples also to the first repo as well?
, да, я добавила! github.com/tanaikech/…
Это еще один метод, с помощью которого вы можете попробовать upload 1,000 files
, но ограничить сценарий 10 files concurrently
за раз.
Вот пример:
После выбора
11 files
first 10
начнет загрузку, а когда они закончатся,11th file
начнет загрузку и завершится.
Это модифицированная версия index.html
:
<input type = "file" id = "file" multiple = "true" />
<input type = "button" onclick = "run()" value = "Upload" />
<div id = "progress"></div>
<script src = "https://cdn.jsdelivr.net/gh/tanaikech/ResumableUploadForGoogleDrive_js@master/resumableupload_js.min.js"></script>
<script>
var q = [];
var c = 10;
function run() {
google.script.run
.withSuccessHandler(accessToken => {
[...document.getElementById("file").files].forEach(file => {
q.push({ file, accessToken });
});
upload();
})
.getAuth();
}
function upload() {
while (q.length > 0 && c > 0) {
const { file, accessToken } = q.shift();
ResumableUploadForGoogleDrive(file, accessToken);
c--;
}
}
function ResumableUploadForGoogleDrive(file, accessToken) {
let fr = new FileReader();
fr.fileName = file.name;
fr.fileSize = file.size;
fr.fileType = file.type;
fr.readAsArrayBuffer(file);
fr.onload = e => {
const id = "p" + Date.now();
const div = document.createElement("div");
div.id = id;
document.getElementById("progress").appendChild(div);
document.getElementById(id).innerHTML = "Initializing.";
const resource = {
fileName: e.target.fileName,
fileSize: e.target.fileSize,
fileType: e.target.fileType,
fileBuffer: e.target.result,
accessToken
};
const ru = new ResumableUploadToGoogleDrive();
ru.Do(resource, (res, err) => {
if (err) {
console.info(err);
return;
}
console.info(res);
let msg = "";
if (res.status === "Uploading") {
msg =
Math.round(
(res.progressNumber.current / res.progressNumber.end) * 100
) +
"% (" +
e.target.fileName +
")";
} else {
msg = res.status + " (" + e.target.fileName + ")";
}
if (res.status === "Done") google.script.run.putFileInf(res.result);
document.getElementById(id).innerText = msg;
if (res.status === "Done") {
c++;
upload();
}
});
};
}
</script>
Переменная
q
хранит выбранные файлы, переменнаяc
служит счетчиком одновременности, а функцияupload()
обрабатывает 10 загрузок за раз.
Это тоже отличное предложение!
Замечательно, что вам указан автор сценария, который вы адаптируете к своим требованиям, однако вопросы на этом сайте должны быть самостоятельными. Учитывая это, добавьте, пожалуйста, минимально воспроизводимый пример.