feat(defer): implement defer (#581)

* feat(defer): implement defer

* make lint happy

* export
This commit is contained in:
D-Sketon 2024-09-24 09:32:09 +08:00 committed by GitHub
parent 8b2cfa0227
commit 36b14bef50
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 143 additions and 0 deletions

View File

@ -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);
});
});

View File

@ -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 isnt 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<F extends (...args: any[]) => any>(func: F, ...args: Parameters<F>): number;
```
### Parameters
- `func` (`F`): The function to defer.
- `args` (`Parameters<F>`, 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.
```

View File

@ -0,0 +1,36 @@
# defer
::: info
出于兼容性原因,此函数仅在 `es-toolkit/compat` 中提供。它可能具有替代的原生 JavaScript API或者尚未完全优化。
`es-toolkit/compat` 导入时,它的行为与 lodash 完全一致,并提供相同的功能,详情请见 [这里](../../../compatibility.md)。
:::
延迟调用 `func`,直到当前堆栈清理完毕。调用时,任何附加的参数会传给 `func`
## 签名
```typescript
function defer<F extends (...args: any[]) => any>(func: F, ...args: Parameters<F>): number;
```
### 参数
- `func` (`F`): 要延迟调用的函数。
- `args` (`Parameters<F>`, 可选): 调用 `func` 时提供的参数。
### 返回值
(`number`): 返回计时器 ID。
## 示例
```typescript
import { defer } from 'es-toolkit/compat';
defer(text => {
console.log(text);
}, 'deferred');
// => 在当前调用栈已清空后打印 'deferred'。
```

View File

@ -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);
});
});

View File

@ -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<F>} 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<F extends (...args: any[]) => any>(func: F, ...args: Parameters<F>): number {
if (typeof func !== 'function') {
throw new TypeError('Expected a function');
}
return setTimeout(func, 1, ...args);
}

View File

@ -48,6 +48,7 @@ export { head as first } from '../array/head.ts';
export { ary } from './function/ary.ts'; export { ary } from './function/ary.ts';
export { bind } from './function/bind.ts'; export { bind } from './function/bind.ts';
export { bindKey } from './function/bindKey.ts'; export { bindKey } from './function/bindKey.ts';
export { defer } from './function/defer.ts';
export { rest } from './function/rest.ts'; export { rest } from './function/rest.ts';
export { spread } from './function/spread.ts'; export { spread } from './function/spread.ts';
export { attempt } from './function/attempt.ts'; export { attempt } from './function/attempt.ts';