Я создаю простой SFTP-клиент с Electron, и я пытаюсь загрузить или загрузить несколько файлов одновременно, используя модуль ssh2 и SFTPStream в этом модуле. Я пробовал много различных структур методов, некоторые из которых включают использование es6-обещания-пула. Каждая попытка сделать результаты приводит к тому, что один файл из массива файлов передается должным образом, а затем

MaxListenersExceededWarning: Обнаружена возможная утечка памяти в EventEmitter. 11 слушателей sftp_message добавлены в [EventEmitter]. Используйте emitter.setMaxListeners () для увеличения лимита

сообщение отображается в консоли, а остальные файлы не передаются. Я не уверен, как изменить структуру моего метода, чтобы предотвратить это. Я использую ipcRenderer, чтобы сказать ipcMain выполнить методы, которые я покажу здесь (вот моя структура для загрузки файлов, например).

let counter = 0;

// Upload local file to server
ipcMain.on('upload_local_files', (event, args) => { // args[0] is connection settings, args[1] is array of file paths
  let conn = new Client();
  conn.on('ready', () => {
    let pool = new PromisePool(uploadFileProducer(conn, args[1]), 10);
    pool.start().then(() => {
      conn.end();
      counter = 0;
      let tempArgs = [];
      tempArgs.push(curLocalDir);
      tempArgs.push(curRemoteDir);
      event.sender.send('local_upload_complete', tempArgs);
    });
  }).connect(args[0]);
});

// Producer used in promise pool to upload files
function uploadFileProducer(conn, files){
  if(counter < 100 && counter < files.length){
    counter++;
    return(uploadFile(conn, files[counter - 1]));
  }else{
    return null;
  }
}

// Function used to upload files in promise pool
function uploadFile(conn, file){
  return new Promise((resolve, reject) => {
    conn.sftp((error, sftp) => {
      return sftp.fastPut(file, curRemoteDir + file.substring(file.lastIndexOf('/') + 1), {}, (error) => {
        resolve(file);
      });
    });
  });
}

По общему признанию, использование пулов обещаний является новым для меня, и я не уверен, собираюсь ли я использовать их должным образом. В другом посте на эту тему использовались пулы обещаний, чтобы предотвратить возникновение проблемы, но в этом примере не было приложения Electron (я не знаю, уместно ли это). Я ценю любую помощь, которую я могу получить!

3
mandrews6975 21 Дек 2019 в 03:33

1 ответ

Лучший ответ

Проблема не в Warning, это просто предупреждение, и обычно в вашем текущем случае использования. Проблема с загрузками заключается в неправильном использовании PromisePool.

Я предполагаю, что вы используете ES6 - обещание бассейн

Вы должны передать функцию производителя обещания в конструктор, но вместо этого вы вызываете функцию и передаете обещание, поэтому загружаются только отдельные файлы.

Вы должны передать производителя, не вызывая его, или сделать производителя, который возвращает функцию, или использовать генератор.

Конструктор PromisePool принимает функцию Promise в качестве первого аргумента.

function *uploadFileProducer(conn, files) {
    for(const file of files)
        yield uploadFile(conn, file);
}

Теперь вы можете позвонить:

let pool = new PromisePool(uploadFileProducer(conn, args[1]), 10)

И PromisePool будет правильно выполнять итерацию, возвращаемую функцией генератора, и соответственно обрабатывать параллелизм.

Вы также можете создать функцию, которая будет возвращать Promise каждый вызов.

function uploadFileProducer(conn, files) {
  files = files.slice(); // don't want to mutate the original
  return () => uploadFile(conn, files.shift())
}

Что касается предупреждения, это нормально, если вы загружаете несколько вещей одновременно, если это так, вы можете увеличить лимит, используя:

emitter.setMaxListeners(n)
1
Marcos Casagrande 21 Дек 2019 в 01:07