程序员的知识教程库

网站首页 > 教程分享 正文

Delay.js:且看前端大神如何延迟 Promise ?

henian88 2024-09-01 18:02:35 教程分享 2 ℃ 0 评论

家好,很高兴又见面了,我是"高级前端?进阶?",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。

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

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表