Как использовать await с promisify для crypto.randomBytes? - PullRequest
0 голосов
/ 30 апреля 2020

Я пишу функцию для генерации случайного ключа с использованием crypto.randomBytes, которая принимает обратный вызов. Я бы предпочел использовать asyn c await, поэтому я пытаюсь использовать util.promisify для переноса случайных байтов следующим образом:

const crypto = require('crypto');
const util = require('util');

const randBytes = util.promisify(crypto.randomBytes);

async function genRandKey() {

  bytes = await randBytes(48).catch((err) => {
    console.log(err);
  });

  return bytes.toString('hex');
}

let result = genRandKey();
console.log('key: ', result);

Но это печатает key: Promise { <pending> } вместо вывода разрешенного значения. Что я тут не так делаю?

Ответы [ 2 ]

2 голосов
/ 30 апреля 2020

Все функции async возвращают обещание. Так что ваша функция genRandKey() также возвращает обещание. Вы должны использовать await или .then() для результата из genRandKey(). То, что вы конвертировали в обещание и использовали await, не означает, что вы можете напрямую вернуть значение из функции. Это не то, что происходит в async функции. Значение return в функции async просто становится разрешенным значением обещания, которое возвращает функция. Хотя код выглядит так, как будто вы возвращаете значение напрямую, это не то, что происходит на самом деле.

В Javascript / node.js НЕТ способа получить асинхронно полученное значение и вернуть его непосредственно из функции , Он должен быть передан обратно через обещание или обратный вызов или событие. Обойти это невозможно.


Теперь в этом конкретном случае c существует синхронная версия crypto.randomBytes(), и вы можете использовать ее вместо этого. Асинхронная версия существует по причине, потому что crypto.randomBytes() требуется немного времени для запуска, и если вы используете синхронную версию, она заблокирует событие l oop во время работы. В зависимости от того, что именно вы делаете, это может быть или не быть проблемой. Асинхронная версия crypto.randomBytes() выполняет фактические операции шифрования в отдельном потоке (используя пул потоков libuv) и возвращает значение асинхронно, чтобы не блокировать событие l oop.

1 голос
/ 30 апреля 2020

Функция asyn c genRandKey() вызывается синхронно, поэтому она возвращает Promise. Вы можете использовать функцию .then() для записи в консоль после завершения функции. Вам необходимо изменить следующий код:

let result = genRandKey();
console.log('key: ', result);

на

genRandKey().then((result) => {
    console.log('key: ', result);
});

Однако это приведет к асинхронному вызову функции во время выполнения остальной части кода. Решение может заключаться в том, чтобы обернуть всю программу в самовыполняющуюся асинхронную c функцию и использовать ключевое слово await:

(async () => {
    const crypto = require('crypto');
    const util = require('util');

    const randBytes = util.promisify(crypto.randomBytes);

    async function genRandKey() {
        bytes = await randBytes(48).catch((err) => {
            console.log(err);
        });

        return bytes.toString('hex');
    }

    let result = await genRandKey();
    console.log('key: ', result);
})();

В качестве альтернативы, вы можете просто поместить оставшуюся часть кода в .then() функция:

const crypto = require('crypto');
const util = require('util');

const randBytes = util.promisify(crypto.randomBytes);

async function genRandKey() {
    bytes = await randBytes(48).catch((err) => {
        console.log(err);
    });

    return bytes.toString('hex');
}

genRandKey().then((result) => {
    console.log('key: ', result);

    ...rest of code...
});
...