问题
I'm writing a function to generate a random key using crypto.randomBytes, which takes a callback. I'd prefer to use async await so I'm trying to use util.promisify to wraprandom bytes like this:
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);
But this prints key: Promise { <pending> }
instead of printing the resolved value. What am I doing wrong here?
回答1:
All async
functions return a promise., So your genRandKey()
function returns a promise too. You have to use await
or .then()
on the result from genRandKey()
. Just because you converted to a promise and used await
does not mean you can directly return the value from the function. That's not what is happening in an async
function. The return
value in an async
function just becomes the resolved value of the promise that the function returns. While, the code looks like you are returning the value directly, that's not what is actually happening.
In Javascript/node.js, there is NO way to take an asynchronously retrieved value and return it directly from a function. It has to be communicated back via a promise or a callback or an event. There is no way around it.
Now, in this specific case, there IS a synchronous version of crypto.randomBytes()
and you could use that instead. The asynchronous version exists for a reason because crypto.randomBytes()
takes a little while to run and if you use the synchronous version, it will block the event loop while it is running. Depending upon exactly what you are doing, this may or may not be a problem . The asynchronous version of crypto.randomBytes()
runs the actual crypto operations in a separate thread (using the libuv thread pool) and returns the value asynchronously so it doesn't block the event loop.
回答2:
The async function genRandKey()
is being called synchronously, so it will return a Promise
. You can use the .then()
function to write to the console after the function has completed. You need to change the following code:
let result = genRandKey();
console.log('key: ', result);
to
genRandKey().then((result) => {
console.log('key: ', result);
});
However, this will cause the function to be called asynchronously while the rest of your code runs. A solution could be to wrap your whole program in a self-executing async function and use the await
keyword:
(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);
})();
Alternatively, you could just put the rest of the code in the .then()
function:
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...
});
来源:https://stackoverflow.com/questions/61528374/how-to-use-await-with-promisify-for-crypto-randombytes