如何使用 await 和 promisify for crypto.randomBytes?

How to use await with promisify for crypto.randomBytes?

我正在编写一个使用 crypto.randomBytes 生成随机密钥的函数,它需要一个回调。我更喜欢使用异步等待,所以我尝试使用 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> } 而不是打印解析后的值。我在这里做错了什么?

所有 async 函数 return 一个承诺。所以你的 genRandKey() 函数 return 也是一个承诺。您必须对 genRandKey() 的结果使用 await.then()。仅仅因为您转换为承诺并使用 await 并不意味着您可以直接 return 函数中的值。这不是 async 函数中发生的事情。 async 函数中的 return 值只是成为函数 returns 的承诺的解析值。虽然,代码看起来像您 return 直接输入值,但实际情况并非如此。

在 Javascript/node.js 中,没有办法直接从函数中获取异步检索的值和 return。它必须通过承诺或回调或事件进行反馈。没办法了。


现在,在这种特定情况下,有 crypto.randomBytes() 的同步版本,您可以改用它。异步版本的存在是有原因的,因为 crypto.randomBytes() 需要一点时间到 运行,如果你使用同步版本,它会在 运行ning 时阻塞事件循环。这可能是问题,也可能不是问题,具体取决于您在做什么。 crypto.randomBytes() 运行 的异步版本在单独的线程(使用 libuv 线程池)中执行实际的加密操作,并且 return 异步地执行值,因此它不会阻塞事件循环。

正在同步调用异步函数 genRandKey(),因此它将 return 一个 Promise。您可以在函数完成后使用 .then() 函数写入控制台。您需要更改以下代码:

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

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

但是,这会导致在其余代码运行时异步调用该函数。一个解决方案可能是将整个程序包装在一个自执行的异步函数中并使用 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...
});