LINUX.ORG.RU

async await в node.js

 ,


0

1

Как вернуть непустой массив, если он заполняется в асинхронщине?

// test.js

function sleep(d) {
  d += Date.now();
  while (Date.now() < d) {};
}

for (let i = 0; i < 3; i++) {
  process.stdout.write(`${process.argv[2]}${i}`);
  sleep(1000);
}
// run-proc.js

const child_process = require("child_process");

function run_proc() {
  let arr = [];
  const proc = child_process.spawn("node", ["./test.js", "#"]);
  proc.stdout.on("data", (data) => {
    console.log(`${data}`);
    arr.push(`${data}`);
  });
  return arr;
}

console.log(run_proc());
node run-proc.js

[]
#0
#1
#2

Up

Выводит err, out при выполнении и сохраняет в Buffer. Алсо, не ломает бинарный вывод.

const child_process = require("child_process");

function run_proc(cmd, args) {
  return new Promise((resolve, reject) => {
    const proc = child_process.spawn(cmd, args);
    let stdout = [];
    let stderr = [];
    proc.stdout.on("data", (data) => {
      console.log(`${data}`);
      stdout.push(data);
    });
    proc.stderr.on("data", (data) => {
      console.error(`${data}`);
      stderr.push(data);
    });
    proc.on("close", (code) => {
      console.log(`close: ${code}`);
      resolve(Buffer.concat(stdout));
      reject(Buffer.concat(stderr));
    });
  });
}

(async () => {
  let arr = [];
  await run_proc("node", ["./test.js", "#"])
  .then(
    stdout => {
      console.log(`${stdout}`);
      arr.push(stdout);
    },
    stderr => {
      console.error(`${stderr}`);
    }
  );
  console.log(Buffer.concat(arr).length);
})();

Ответ на: комментарий от menangen

Ну, это специфично для child_process. А в общем случае? Некая асинхронная функция что-то выдает. Надо собрать и неоднократно использовать.

slavamn ()
Ответ на: комментарий от slavamn

общий ответ на общий вопрос

А в общем случае? Некая асинхронная функция что-то выдает. Надо собрать и неоднократно использовать.

Результаты вызовов нескольких асинхронных функций (если ты используешь оператор async, то при вызове будет возвращаться тип Promise), например, таких:

const yieldNumber = () => new Promise((res, rej) => {
  setTimeout(() => {
    res(Math.random())
  }, 100)
});

можно легко собрать с помощью Promise.all в один массив:

Promise.all([
  yieldNumber(),
  yieldNumber(),
  yieldNumber(),
  yieldNumber()
]).then(numbers => {
  // здесь делаем что-нибудь с нашими числами
})

Например:

let numbers = []; // создадим хранилище

Promise.all([
  yieldNumber(), // эту функцию мы обьявили ранее
  yieldNumber(),
  yieldNumber(),
  yieldNumber()
]).then(yoldNumbers => {
  numbers = yoldNumbers;
  
  return numbers
}).then(console.log) // только в этом then наш код будет знать, что numbers изменён!

Выведет в консоль:

[
  0.6974620730153078,
  0.876047460204964,
  0.014076783113265878,
  0.8746765911066423
]

Хранилище для полученных асинхронно данных лучше, конечно, делать не в виде переменной, а сразу классом:

class NumberStorage {
  numbers = []
}

const randomNumberStorage = new NumberStorage();

Promise.all([
  yieldNumber(),
  yieldNumber(),
  yieldNumber(),
  yieldNumber()
]).then(yoldNumbers => {
  randomNumberStorage.numbers = yoldNumbers
}).then(() => {
  console.log(randomNumberStorage.numbers) // результат, аналогичный предыдущему примеру
})

Чтобы не запутаться, можешь пользоваться деструктуризацией:

Promise.all([
  yieldNumber(), // эту функцию мы обьявили ранее
  yieldNumber(),
  yieldNumber(),
  yieldNumber()
]).then(([
  fst,
  snd,
  thrd,
  lst
]) => console.table({
  fst,
  snd,
  thrd,
  lst
}))
Princesska ★★★★ ()
Последнее исправление: Princesska (всего исправлений: 2)
Ответ на: общий ответ на общий вопрос от Princesska

а теперь более подробно

Итак, после обьявления функции generateNumbers, создадим снова класс хранилища и один его экземпляр:

class NumberStorage {
  numbers = []
}

const randomNumbers = new NumberStorage();

Допустим, в какой-то момент времени пользователь может вызвать событие, по которому нужно будет что-нибудь сделать с сохранёнными числами, которые мы получили, вызвав эту асинхронную функцию:

const RandomNumbersRequestEventName =
  'USER_REQUESTED_RANDOM_NUMBERS';

const RandomNumbersRequestEvent =
  new Event('USER_REQUESTED_RANDOM_NUMBERS');

Сразу обьявим функцию, которая сразу выдаст нам семь случайных чисел асинхронно:

const generateNumbers = () => Promise.all([
  yieldNumber(),
  yieldNumber(),
  yieldNumber(),
  yieldNumber(),
  yieldNumber(),
  yieldNumber(),
  yieldNumber()
]);

Подпишемся на пользовательское событие. Когда оно сработает, выведем в консоль сохранённые случайные числа:

document.addEventListener(RandomNumbersRequestEventName, () => {
  console.log(randomNumbers.numbers)
});

Пробуем:

generateNumbers().then(yoldNumbers => {
  randomNumbers.numbers = yoldNumbers;
  document.dispatchEvent(RandomNumbersRequestEvent);
});

В консоли:

[
    0.8872287671382095,
    0.7172581179106962,
    0.05839421962575797,
    0.5242367566531021,
    0.17818883298275945,
    0.8817627286025163,
    0.15011330754427
]
Princesska ★★★★ ()
Ответ на: а теперь более подробно от Princesska

Спасибо большое!

Только от const yieldNumber = () => new Promise((res, rej) => { у меня парсер ломается.

Это то же самое ведь будет?

function yieldNumber() {
  return new Promise((res, rej) => {
    setTimeout(() => {
      res(Math.random())
    }, 100)
  });
}

slavamn ()
var args = [1,2,3];
var res = await Promise.All(
   agrs.map(arg=>your_async_function(arg))
);
crutch_master ★★★★★ ()
Последнее исправление: crutch_master (всего исправлений: 4)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.