Ожидание обещания перед обратным вызовом в async.each

router.post('/runCommand', async function(req, res){
  let results = [];
  async.each(req.body.requests, async function(request, callback){
    const data = await connect(request.command)
    await results.push(data);
    await callback(null);
  }, function(err){
    if (!err) {
      res.send(202, results)
    }
  })
})

Res.send никогда не выполняется, и кажется, что обратный вызов происходит до завершения подключения. Connect успешно возвращает обещание, потому что это

router.get('/topics', async function(req, res) {
  console.info('in get');
  const data = await connect(req.body.command);
  await res.send(data);
});

работает отлично. Но включение async.each для запуска нескольких команд кажется неработающим. Я знаю, что это проблема с тем, как я вызываю функцию обратного вызова async.each, но исследования не помогли, как я должен ее называть. Можно ли использовать .then() после ожидания обещания?

function connect(command){
  return new Promise(function(resolve) {
  let host = {
        server: {
          host: "host",
          port: "port",
          userName: "user",
          password: config.Devpassword
        },
        commands: [ command ]
      };
  var SSH2Shell = require ('ssh2shell'),
  //Create a new instance passing in the host object
  SSH = new SSH2Shell(host),
  //Use a callback function to process the full session text
  callback = function(sessionText){
    console.info(sessionText)
    resolve(sessionText);
  }
  SSH.connect(callback);
  })
};

Вы когда-нибудь звонили на ваш обратный звонок на async.each()? Если да, то о какой ошибке было сообщено? Здесь недостаточно информации, чтобы определить, в чем вы ошибаетесь. Вы уверены, что req.body вашего запроса POST будет отформатирован как { requests: [ { command: ... }, ...] }?

Patrick Roberts 26.10.2018 18:31

По журналам консоли в функции подключения я могу сказать, что это происходит для каждой команды в req. и да, это правильный формат. Проблема, с которой я сталкиваюсь, связана с запуском обратного вызова. Я не жду подключения для завершения работы. поэтому async.each выполняет каждую команду в req до того, как массив результатов будет правильно определен. Хотя я не уверен, почему res.send никогда не происходит. Я предполагал, что он просто отправит массив невыполненных обещаний, но на самом деле никогда не отправляет

Noah Rolf 26.10.2018 18:37

Пожалуйста, предоставьте источник connect(), отправив свой ответ редактироватьRing. Похоже, проблема в этом.

Patrick Roberts 26.10.2018 18:40

И вы получаете console.info(sessionText) на каждый request в req.body.requests?

Patrick Roberts 26.10.2018 18:45

@PatrickRoberts Я добавил исходный код для connect(), хотя не верю, что проблема существует. Возвращает обещание штрафа. Когда я запускаю только одну команду с другой функцией, она должным образом ожидает ее завершения перед повторной отправкой текста сеанса. Я думаю, проблема в том, как я вызываю callback () из async.each

Noah Rolf 26.10.2018 18:45

да, я попытался передать 3 команды, и журнал консоли появился для всех 3

Noah Rolf 26.10.2018 18:45

Попробуйте callback() вместо callback(null). Я был бы удивлен, если это сработает, но это единственное, что кажется возможным здесь изменить. Вы неправильно используете await в нескольких местах, но это не влияет на то, что должно произойти.

Patrick Roberts 26.10.2018 18:50

@PatrickRoberts, как ни странно, удаление null по крайней мере сделало так, чтобы был вызван res.send. Но он отправил только пустой массив вместо массива sessionTexts. Итак, callback() определенно работает до завершения подключения. Можно ли переформатировать подключение к const data = await connect().then( callback() )

Noah Rolf 26.10.2018 19:09

Вы уверены, что опубликованный вами источник router.post() - это то, что вы на самом деле используете? Я не хочу сказать, что задаю очевидный вопрос; Я спрашиваю, потому что спрашивающие обычно удаляют код в опубликованных фрагментах для краткости или по причинам собственности, а иногда эти удаления приводят к тому, что минимальный пример ведет себя иначе.

Patrick Roberts 26.10.2018 19:15

И нет, предложенное вами изменение не сработает по нескольким причинам.

Patrick Roberts 26.10.2018 19:16

Да, я дважды проверил. Он идентичен, вплоть до имен функций и переменных.

Noah Rolf 26.10.2018 19:16

Я все еще пытаюсь разобраться в этой проблеме. Мне это кажется очень странным.

Patrick Roberts 26.10.2018 19:28
Поведение ключевого слова "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
12
449
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Хотя вы могли бы и дальше тратить больше времени на то, чтобы заставить async.each() работать, я рекомендую просто отказаться от него и использовать исключительно синтаксис async / await, который значительно упрощает ваш код:

router.post('/runCommand', async function (req, res) {
  try {
    const results = await Promise.all(
      req.body.requests.map(({ command }) => connect(command))
    );

    res.send(202, results);
  } catch ({ message, stack }) {
    res.send(500, { error: message, stack });
  }
})

Глядя на документацию ssh2shell, я думаю, что ваша функция connect также может быть улучшена для лучшей читаемости и обработки ошибок:

const SSH2Shell = require('ssh2shell');

function connect (command) {
  return new Promise((resolve, reject) => {
    const host = {
      server: {
        host: 'host',
        port: 'port',
        userName: 'user',
        password: config.Devpassword
      },
      commands: [command]
    };
    //Create a new instance passing in the host object
    const SSH = new SSH2Shell(host);

    SSH.on('error', reject);
    SSH.connect(resolve);
  });
}

Не стесняйтесь комментировать, если это все еще не работает для вас.

Благодарность! Вы были на 100% правы, говоря об упрощении. Я обязательно воспользуюсь этим, но, возможно, изучу async.each, когда у меня будет больше времени.

Noah Rolf 26.10.2018 20:10

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