const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
Is the essence of the implementation of util.promisify(setTimeout)
, but there are additional features to the promisify
implementation:
- it takes an optional value argument that is returned as the value of the promise
setTimeoutPromisify(10, 'foo bar').then(value => console.log(value)) // logs "foo bar"
console.log(await setTimeoutPromisify(10, 'foo bar')) // logs "foo bar"
- it takes an (optional) options argument that
- lets you specify an
AbortController
signal
to cancel the timeout
- lets you choose whether or not to keep a
ref
, which if set to false, means the program will exit before the timeout finishes if nothing else is happening
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()
For more information see https://nodejs.org/api/timers.html
The implementation in node 16 is below:
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;
}