环境:节点8.11.x 我想使用async / await睡眠一会儿。
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
await sleep(5000)
这有效。
const sleep = util.promisify(setTimeout)
await sleep(5000)
它会导致异常:TypeError:“回调”参数必须是一个函数。 setTimeout文档注释:此方法具有一个针对promise的自定义变体,可使用util.promisify()
那有什么区别?
答案 0 :(得分:1)
这可以是一个单行:await promisify(setTimeout)(1000)
。
它起作用,因为setTimeout有一个custom variant for promisify。确实适用于节点8.11。
nvm install 8.11 && nvm use 8.11
node <<HEREDOC
(async () => {
// const start = Date.now();
await require('util').promisify(setTimeout)(5000);
// console.log(Date.now() - start);
})()
HEREDOC
答案 1 :(得分:0)
promisify
期望一个函数的最终参数为回调。
换句话说,它想要一个看起来像这样的函数:
function takesACallback(str, Fn) {
Fn(null, "got: ", str)
// or with an error:
// Fn(error)
}
当然setTimout
相反。您要传递的参数是最后一个参数。因此,当您尝试调用promisify
d函数并传入一个参数时,它将采用该参数-延迟-并尝试像函数一样调用它。当然,这是一个错误。
仅出于娱乐(和轻微的教育目的)目的,您可以传入一个可以反转参数的函数,它将起作用:
let util = require('util')
let pause = util.promisify((a, f) => setTimeout(f, a))
pause(2000)
.then(() => console.log("done"))
现在,您传递给promisify
的函数的最后一个参数需要函数。但是asyn/await
方法如此好得多……
答案 2 :(得分:0)
您知道这里的功能有效:
const {promisify} = require('util');
const sleep = promisify(setTimeout);
;(async () => {
const ts = Date.now()
await sleep(5000)
console.log(Date.now()-ts)
})();
这很好用,为什么不去使用它呢?
答案 3 :(得分:0)
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
是 util.promisify(setTimeout)
实现的本质,但 promisify
实现还有其他功能:
setTimeoutPromisify(10, 'foo bar').then(value => console.log(value)) // logs "foo bar"
console.log(await setTimeoutPromisify(10, 'foo bar')) // logs "foo bar"
AbortController
signal
以取消超时ref
,如果设置为 false,则表示如果没有其他事情发生,程序将在超时完成之前退出const controller = new AbortController();
const signal = ac.signal;
setTimeoutPromisify(1000, 'foo bar', { signal, ref: true })
.then(console.log)
.catch((err) => {
if (err.name === 'AbortError')
console.log('The timeout was aborted');
})
controller.abort()
有关详细信息,请参阅 https://nodejs.org/api/timers.html
节点 16 中的实现如下:
function setTimeout(after, value, options = {}) {
const args = value !== undefined ? [value] : value;
if (options == null || typeof options !== 'object') {
return PromiseReject(
new ERR_INVALID_ARG_TYPE(
'options',
'Object',
options));
}
const { signal, ref = true } = options;
try {
validateAbortSignal(signal, 'options.signal');
} catch (err) {
return PromiseReject(err);
}
if (typeof ref !== 'boolean') {
return PromiseReject(
new ERR_INVALID_ARG_TYPE(
'options.ref',
'boolean',
ref));
}
if (signal && signal.aborted) {
return PromiseReject(new AbortError());
}
let oncancel;
const ret = new Promise((resolve, reject) => {
const timeout = new Timeout(resolve, after, args, false, true);
if (!ref) timeout.unref();
insert(timeout, timeout._idleTimeout);
if (signal) {
oncancel = FunctionPrototypeBind(cancelListenerHandler,
timeout, clearTimeout, reject);
signal.addEventListener('abort', oncancel);
}
});
return oncancel !== undefined ?
PromisePrototypeFinally(
ret,
() => signal.removeEventListener('abort', oncancel)) : ret;
}