大家好,很高兴又见面了,我是"高级前端?进阶?",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。
1.什么是 Delay
由前端大神 sindresorhus 开发的 Delay 库用于将 Promise 延迟指定的时间。
当然,如果开发者仅针对 Node.js,则可以使用如下方式:
import {setTimeout} from 'node:timers/promises';
await setTimeout(1000);
如果需要浏览器支持该功能,可以使用这个包仍。
2.如何使用 Delay
延迟指定时间
import delay from 'delay';
bar();
await delay(100);
// 100ms后执行
baz();
延迟后返回指定的值
import delay from 'delay';
const result = await delay(100, {value: ''});
// Executed after 100 milliseconds
console.log(result);
// 返回值 => ''
取消延迟
如果信号被中止,返回的 Promise 将被reject,并出现 AbortError。
import delay from 'delay';
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, 500);
try {
await delay(1000, {signal: abortController.signal});
} catch (error) {
// 500 milliseconds later
console.log(error.name)
//=> 输出 'AbortError'
}
清除延迟并resolve Promise
如果传递一个已经 resolve 的 Promise 或来自其他地方的Promise,它不会执行任何操作。
import delay, {clearDelay} from 'delay';
const delayedPromise = delay(1000, {value: 'Done'});
setTimeout(() => {
clearDelay(delayedPromise);
}, 500);
// 500 milliseconds later
console.log(await delayedPromise);
//=> 输出 'Done'
使用createDelay({clearTimeout, setTimeout})
使用提供的函数创建一个新的delay实例来清除和设置超时。如果要在全局范围内存根计时器,但仍然想使用delay来管理测试,那么这很有用。
import {createDelay} from 'delay';
const customDelay = createDelay({clearTimeout, setTimeout});
const result = await customDelay(100, {value: ''});
// Executed after 100 milliseconds
console.log(result);
// 输出 => ''
3.Delay源码
接下来一起看看delay延迟的源码实现,具体代码逻辑可以参考注释。
// From https://github.com/sindresorhus/random-int/blob/c37741b56f76b9160b0b63dae4e9c64875128146/index.js#L13-L15
const randomInteger = (minimum, maximum) => Math.floor((Math.random() * (maximum - minimum + 1)) + minimum);
const createAbortError = () => {
const error = new Error('Delay aborted');
error.name = 'AbortError';
return error;
};
const clearMethods = new WeakMap();
export function createDelay({clearTimeout: defaultClear, setTimeout: defaultSet} = {}) {
// 不能在这里使用“async”,因为我们需要 Promise 身份。
return (milliseconds, {value, signal} = {}) => {
// TODO: Use `signal?.throwIfAborted()` when targeting Node.js 18.
if (signal?.aborted) {
return Promise.reject(createAbortError());
}
// 如何signal被取消,则直接reject
let timeoutId;
let settle;
let rejectFunction;
const clear = defaultClear ?? clearTimeout;
const signalListener = () => {
clear(timeoutId);
rejectFunction(createAbortError());
};
const cleanup = () => {
// 移除事件
if (signal) {
signal.removeEventListener('abort', signalListener);
}
};
const delayPromise = new Promise((resolve, reject) => {
settle = () => {
cleanup();
resolve(value);
};
rejectFunction = reject;
timeoutId = (defaultSet ?? setTimeout)(settle, milliseconds);
});
// 监听abort事件
if (signal) {
signal.addEventListener('abort', signalListener, {once: true});
}
// 延迟promise
clearMethods.set(delayPromise, () => {
clear(timeoutId);
timeoutId = null;
settle();
});
return delayPromise;
};
}
const delay = createDelay();
export default delay;
// 导出delay
export async function rangeDelay(minimum, maximum, options = {}) {
return delay(randomInteger(minimum, maximum), options);
}
export function clearDelay(promise) {
clearMethods.get(promise)?.();
}
下面是与Delay类似的相关库:
- delay-cli :此模块的 CLI
- p-cancelable : 创建一个可以取消的 Promise
- p-min-delay : 将 Promise 延迟最短时间
- p-immediate:Promise 返回下一个事件循环中 resolve的 Promise ,类似 setImmediate
- p-timeout :在指定时间后超时 Promise
参考资料
https://github.com/sindresorhus/delay
https://github.com/sindresorhus/promise-fun
https://bobbyhadz.com/blog/javascript-resolve-promise-after-delay
https://dmitripavlutin.com/javascript-promises-settimeout/
https://dev.to/oliverjumpertz/javascript-quick-tip-create-a-cancelable-promise-delay-52fb
本文暂时没有评论,来添加一个吧(●'◡'●)