Skip to content

Commit

Permalink
feat: add singleton
Browse files Browse the repository at this point in the history
  • Loading branch information
surunzi committed Nov 1, 2024
1 parent f94352d commit bebc00a
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 0 deletions.
35 changes: 35 additions & 0 deletions DOC.md
Original file line number Diff line number Diff line change
Expand Up @@ -12350,6 +12350,41 @@ function shuffle(arr: any[]): any[];
shuffle([1, 2, 3]); // -> [3, 1, 2]
```

## singleton

Ensure an async function is only called once before it resolves.

<details>
<summary>Type Definition</summary>

```typescript
function singleton<F extends types.Fn<Promise<any>>>(
fn: F,
hashFn?: types.AnyFn
): F;
```

</details>

|Name |Desc |
|------|----------------------------|
|fn |Function to restrict |
|hashFn|Function to create cache key|
|return|New restricted function |

```javascript
const fetch = singleton(async function fetch(id) {});
const f1 = fetch(1);
const f2 = fetch(1);
const f3 = fetch(2);
console.log(f1 === f2); // -> true
console.log(f1 === f3); // -> false

await f1;
const f4 = fetch(1);
console.log(f1 === f4); // -> false
```

## size

Get size of object or length of array like object.
Expand Down
35 changes: 35 additions & 0 deletions DOC_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -12341,6 +12341,41 @@ function shuffle(arr: any[]): any[];
shuffle([1, 2, 3]); // -> [3, 1, 2]
```

## singleton

确保一个异步函数返回前只运行一个实例。

<details>
<summary>类型定义</summary>

```typescript
function singleton<F extends types.Fn<Promise<any>>>(
fn: F,
hashFn?: types.AnyFn
): F;
```

</details>

|参数名|说明|
|-----|---|
|fn|要限制的函数|
|hashFn|计算缓存键名函数|
|返回值|单例运行函数|

```javascript
const fetch = singleton(async function fetch(id) {});
const f1 = fetch(1);
const f2 = fetch(1);
const f3 = fetch(2);
console.log(f1 === f2); // -> true
console.log(f1 === f3); // -> false

await f1;
const f4 = fetch(1);
console.log(f1 === f4); // -> false
```

## size

获取对象的大小或类数组元素的长度。
Expand Down
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@
"shellSort",
"shuffle",
"SingleEmitter",
"singleton",
"size",
"sizeof",
"sleep",
Expand Down
9 changes: 9 additions & 0 deletions i18n/singleton.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## CN

确保一个异步函数返回前只运行一个实例。

|参数名|说明|
|-----|---|
|fn|要限制的函数|
|hashFn|计算缓存键名函数|
|返回值|单例运行函数|
15 changes: 15 additions & 0 deletions index.json
Original file line number Diff line number Diff line change
Expand Up @@ -5922,6 +5922,21 @@
"browser"
]
},
"singleton": {
"dependencies": [
"has"
],
"description": "Ensure an async function is only called once before it resolves.",
"env": [
"node",
"browser",
"miniprogram"
],
"test": [
"node",
"browser"
]
},
"size": {
"dependencies": [
"isArrLike",
Expand Down
56 changes: 56 additions & 0 deletions src/singleton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* Ensure an async function is only called once before it resolves.
*
* |Name |Desc |
* |------|----------------------------|
* |fn |Function to restrict |
* |hashFn|Function to create cache key|
* |return|New restricted function |
*/

/* example
* const fetch = singleton(async function fetch(id) {});
* const f1 = fetch(1);
* const f2 = fetch(1);
* const f3 = fetch(2);
* console.log(f1 === f2); // -> true
* console.log(f1 === f3); // -> false
*
* await f1;
* const f4 = fetch(1);
* console.log(f1 === f4); // -> false
*/

/* module
* env: all
*/

/* typescript
* export declare function singleton<F extends types.Fn<Promise<any>>>(
* fn: F,
* hashFn?: types.AnyFn
* ): F;
*/

_('types has');

exports = function(fn, hashFn = JSON.stringify) {
const singleton = function() {
const cache = singleton.cache;
const address = hashFn.apply(this, arguments);

if (has(cache, address)) {
return cache[address];
}

const promise = fn.apply(this, arguments).finally(() => {
delete cache[address];
});
cache[address] = promise;

return promise;
};

singleton.cache = {};

return singleton;
};
18 changes: 18 additions & 0 deletions test/singleton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
it('basic', async function() {
const fetch = singleton(async function fetch(id) {
return new Promise(resolve => {
setTimeout(() => {
resolve(id);
}, 100);
});
});
const f1 = fetch(1);
const f2 = fetch(1);
const f3 = fetch(2);
expect(f1).to.equal(f2);
expect(f1).to.not.equal(f3);

expect(await f1).to.equal(1);
const f4 = fetch(1);
expect(f1).to.not.equal(f4);
});

0 comments on commit bebc00a

Please sign in to comment.