Как ограничить асинхронную загрузку x за раз?

Я пытаюсь загрузить файлы через веб-форму на сервер 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>

Замечательно, что вам указан автор сценария, который вы адаптируете к своим требованиям, однако вопросы на этом сайте должны быть самостоятельными. Учитывая это, добавьте, пожалуйста, минимально воспроизводимый пример.

Wicket 16.08.2024 00:36

Обновлено воспроизводимым примером кода.

Dan 16.08.2024 02:13
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
2
53
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

В вашей ситуации как насчет следующего примера сценария?

Прежде чем использовать этот скрипт, включите Drive API в расширенных службах Google.

Скрипт Google Apps: 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);
}

HTML и Javascript: 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 16.08.2024 11:28

@Dan Спасибо за ответ и тестирование. Я рад, что ваша проблема была решена. Спасибо и вам. Насчет Might I suggest to add those Async samples also to the first repo as well?, да, я добавила! github.com/tanaikech/…

Tanaike 16.08.2024 13:29

АЛЬТЕРНАТИВНОЕ РЕШЕНИЕ

Это еще один метод, с помощью которого вы можете попробовать upload 1,000 files, но ограничить сценарий 10 files concurrently за раз.

Вот пример:

После выбора 11 filesfirst 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 загрузок за раз.

ССЫЛКА

Это тоже отличное предложение!

Dan 16.08.2024 11:28

Другие вопросы по теме