Skip to content

Commit

Permalink
feat: new function - onlyResolvesLast
Browse files Browse the repository at this point in the history
  • Loading branch information
GreatAuk committed Feb 25, 2023
1 parent e2eed3a commit 9a0e9b7
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ pnpm add @utopia-utils/dom
* deepEqual: 深拷贝。[source](https://github.com/GreatAuk/utopia-utils/blob/main/packages/core/src/deepEqual.ts)
* compose: 函数组合, 从右到左执行。[source](https://github.com/GreatAuk/utopia-utils/blob/main/packages/core/src/compose.ts)
* pipe: 函数组合, 从左到右执行。[source](https://github.com/GreatAuk/utopia-utils/blob/main/packages/core/src/pipe.ts)
* onlyResolvesLast: 解决竞态问题,只保留最后一次调用的结果。[source](https://github.com/GreatAuk/utopia-utils/blob/main/packages/core/src/onlyResolvesLast.ts)
### 类型判断

```bash
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export * from './math'
export * from './memoize'
export * from './objectKeys'
export * from './omit'
export * from './once'
export * from './onlyResolvesLast'
export * from './pick'
export * from './pipe'
export * from './randomInt'
Expand Down
37 changes: 37 additions & 0 deletions packages/core/src/onlyResolvesLast.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { onlyResolvesLast } from './onlyResolvesLast'

describe('onlyResolvesLast', () => {
it('should resolve the last call', async () => {
const foo_ = async (n: number) => {
return new Promise<number>((resolve) => {
setTimeout(() => resolve(n), Math.random())
})
}
const foo = onlyResolvesLast(foo_)
let lastValue = 0

await Promise.race([
foo(1).then(v => lastValue = v),
foo(2).then(v => lastValue = v),
foo(3).then(v => lastValue = v),
foo(4).then(v => lastValue = v),
])
expect(lastValue).toBe(4)
})
it('should reject the last call', async () => {
const foo_ = async (n: number) => {
return new Promise<number>((resolve, reject) => {
setTimeout(() => reject(n), Math.random())
})
}
const foo = onlyResolvesLast(foo_)
let lastError = 0

await Promise.race([
foo(1).catch(e => lastError = e),
foo(2).catch(e => lastError = e),
foo(3).catch(e => lastError = e),
])
expect(lastError).toBe(3)
})
})
38 changes: 38 additions & 0 deletions packages/core/src/onlyResolvesLast.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* Wraps an async function, and ensures that only last call will ever resolve/reject
* @param {T} fn - T - the function to wrap
* @returns A function that will only resolve the last call.
* @example
* ```
const foo_ = (id: number) => fetch('/api/post/' + id)
const foo = onlyResolvesLast(foo)
foo(1).then(() => console.log('resolved')) // promise will never resolve
foo(2).then(() => console.log('resolved')) // promise will never resolve
foo(3).then(() => console.log('resolved')) // promise will resolve with response
* ```
*/
export function onlyResolvesLast<T extends (...args: any) => Promise<any>>(fn: T) {
let time = 0
function wrappedFn(this: ThisParameterType<T>, ...args: Parameters<T>): ReturnType<T> {
const currentTime = time + 1
time = currentTime

const res = fn.apply(this, args)

return new Promise((resolve, reject) => {
Promise.resolve(res)
.then((res_) => {
// just resolve last call
if (currentTime === time)
resolve(res_)
})
.catch((err) => {
// just resolve last call
if (currentTime === time)
reject(err)
})
}) as any
}

return wrappedFn
}
2 changes: 1 addition & 1 deletion packages/core/src/retry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ describe('retry', async () => {
expect(res).toBe(null)
expect(callNum).toBe(3)
// 1 * 5 + 2 * 5
expect(endTime - startTime).toBeGreaterThanOrEqual(15)
expect(endTime - startTime).toBeGreaterThanOrEqual(14)
})
it('should retry the function with delay (function return promise)', async () => {
let callNum = 0
Expand Down

0 comments on commit 9a0e9b7

Please sign in to comment.