From 36b14bef50715d433d73ecd4b1a757765c4df8b4 Mon Sep 17 00:00:00 2001 From: D-Sketon <2055272094@qq.com> Date: Tue, 24 Sep 2024 09:32:09 +0800 Subject: [PATCH] feat(defer): implement defer (#581) * feat(defer): implement defer * make lint happy * export --- benchmarks/performance/defer.bench.ts | 15 ++++++++ docs/reference/compat/function/defer.md | 35 ++++++++++++++++++ .../reference/compat/function/defer.md | 36 ++++++++++++++++++ src/compat/function/defer.spec.ts | 37 +++++++++++++++++++ src/compat/function/defer.ts | 19 ++++++++++ src/compat/index.ts | 1 + 6 files changed, 143 insertions(+) create mode 100644 benchmarks/performance/defer.bench.ts create mode 100644 docs/reference/compat/function/defer.md create mode 100644 docs/zh_hans/reference/compat/function/defer.md create mode 100644 src/compat/function/defer.spec.ts create mode 100644 src/compat/function/defer.ts diff --git a/benchmarks/performance/defer.bench.ts b/benchmarks/performance/defer.bench.ts new file mode 100644 index 00000000..ffe1015c --- /dev/null +++ b/benchmarks/performance/defer.bench.ts @@ -0,0 +1,15 @@ +import { bench, describe } from 'vitest'; +import { defer as deferToolkit } from 'es-toolkit/compat'; +import { defer as deferLodash } from 'lodash'; + +describe('defer', () => { + bench('es-toolkit/defer', () => { + const id = deferToolkit(() => {}); + clearTimeout(id); + }); + + bench('lodash/defer', () => { + const id = deferLodash(() => {}); + clearTimeout(id); + }); +}); diff --git a/docs/reference/compat/function/defer.md b/docs/reference/compat/function/defer.md new file mode 100644 index 00000000..feefad68 --- /dev/null +++ b/docs/reference/compat/function/defer.md @@ -0,0 +1,35 @@ +# defer + +::: info +This function is only available in `es-toolkit/compat` for compatibility reasons. It either has alternative native JavaScript APIs or isn’t fully optimized yet. + +When imported from `es-toolkit/compat`, it behaves exactly like lodash and provides the same functionalities, as detailed [here](../../../compatibility.md). +::: + +Defers invoking the `func` until the current call stack has cleared. Any additional arguments are provided to `func` when it's invoked. + +## Signature + +```typescript +function defer any>(func: F, ...args: Parameters): number; +``` + +### Parameters + +- `func` (`F`): The function to defer. +- `args` (`Parameters`, optional): The arguments to invoke `func` with. + +### Returns + +(`number`): Returns the timer id. + +## Examples + +```typescript +import { defer } from 'es-toolkit/compat'; + +defer(text => { + console.log(text); +}, 'deferred'); +// => Logs 'deferred' after the current call stack has cleared. +``` diff --git a/docs/zh_hans/reference/compat/function/defer.md b/docs/zh_hans/reference/compat/function/defer.md new file mode 100644 index 00000000..34332f38 --- /dev/null +++ b/docs/zh_hans/reference/compat/function/defer.md @@ -0,0 +1,36 @@ +# defer + +::: info +出于兼容性原因,此函数仅在 `es-toolkit/compat` 中提供。它可能具有替代的原生 JavaScript API,或者尚未完全优化。 + +从 `es-toolkit/compat` 导入时,它的行为与 lodash 完全一致,并提供相同的功能,详情请见 [这里](../../../compatibility.md)。 + +::: + +延迟调用 `func`,直到当前堆栈清理完毕。调用时,任何附加的参数会传给 `func`。 + +## 签名 + +```typescript +function defer any>(func: F, ...args: Parameters): number; +``` + +### 参数 + +- `func` (`F`): 要延迟调用的函数。 +- `args` (`Parameters`, 可选): 调用 `func` 时提供的参数。 + +### 返回值 + +(`number`): 返回计时器 ID。 + +## 示例 + +```typescript +import { defer } from 'es-toolkit/compat'; + +defer(text => { + console.log(text); +}, 'deferred'); +// => 在当前调用栈已清空后打印 'deferred'。 +``` diff --git a/src/compat/function/defer.spec.ts b/src/compat/function/defer.spec.ts new file mode 100644 index 00000000..252fba9b --- /dev/null +++ b/src/compat/function/defer.spec.ts @@ -0,0 +1,37 @@ +import { describe, expect, it } from 'vitest'; +import { defer } from './defer'; + +describe('defer', () => { + it('should provide additional arguments to `func`', (done: () => void) => { + let args: any[]; + + defer( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + function (a: any, b: any) { + // eslint-disable-next-line prefer-rest-params + args = Array.from(arguments); + }, + 1, + 2 + ); + + setTimeout(() => { + expect(args).toEqual([1, 2]); + done(); + }, 32); + }); + + it('should be cancelable', (done: () => void) => { + let pass = true; + const timerId = defer(() => { + pass = false; + }); + + clearTimeout(timerId); + + setTimeout(() => { + expect(pass); + done(); + }, 32); + }); +}); diff --git a/src/compat/function/defer.ts b/src/compat/function/defer.ts new file mode 100644 index 00000000..90087bb3 --- /dev/null +++ b/src/compat/function/defer.ts @@ -0,0 +1,19 @@ +/** + * Defers invoking the `func` until the current call stack has cleared. Any additional arguments are provided to func when it's invoked. + * + * @param {F} func The function to defer. + * @param {Parameters} args The arguments to invoke `func` with. + * @returns {number} Returns the timer id. + * + * @example + * defer((text) => { + * console.log(text); + * }, 'deferred'); + * // => Logs 'deferred' after the current call stack has cleared. + */ +export function defer any>(func: F, ...args: Parameters): number { + if (typeof func !== 'function') { + throw new TypeError('Expected a function'); + } + return setTimeout(func, 1, ...args); +} diff --git a/src/compat/index.ts b/src/compat/index.ts index 339aed05..887b1fb7 100644 --- a/src/compat/index.ts +++ b/src/compat/index.ts @@ -48,6 +48,7 @@ export { head as first } from '../array/head.ts'; export { ary } from './function/ary.ts'; export { bind } from './function/bind.ts'; export { bindKey } from './function/bindKey.ts'; +export { defer } from './function/defer.ts'; export { rest } from './function/rest.ts'; export { spread } from './function/spread.ts'; export { attempt } from './function/attempt.ts';