Skip to content

Commit

Permalink
Fix asPromise race condition
Browse files Browse the repository at this point in the history
  • Loading branch information
pirelenito committed Apr 10, 2024
1 parent 1069c89 commit e22975d
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 14 deletions.
24 changes: 21 additions & 3 deletions packages/@react-facet/core/src/helpers/asPromise.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
import { NO_VALUE } from '..'
import { createFacet } from '../facet'
import { asPromise } from './asPromise'

it('resolves facets with their values if available', async () => {
it('immediately resolves facets with their values if available', async () => {
const facet = createFacet({ initialValue: 'testing' })
const value = await asPromise(facet)
const value = await asPromise(facet).promise
expect(value).toEqual('testing')
})

it.todo('waits for the facet to have a value, making sure to not hold subscriptions')
it('waits for the facet to have a value, making sure to not hold subscriptions', async () => {
const cleanupSubscription = jest.fn()
const startSubscription = jest.fn().mockImplementation((update) => {
update('testing')
return cleanupSubscription
})

const facet = createFacet<string>({
initialValue: NO_VALUE,
startSubscription,
})

const value = await asPromise(facet).promise
expect(value).toEqual('testing')

expect(startSubscription).toHaveBeenCalledTimes(1)
expect(cleanupSubscription).toHaveBeenCalledTimes(1)
})
38 changes: 27 additions & 11 deletions packages/@react-facet/core/src/helpers/asPromise.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,37 @@
import { Facet, NO_VALUE } from '../types'

/**
* Takes a Facet as returns a Promise that will resolve with its first value
* Takes a Facet and returns a Promise that will resolve with its first value
*
* @param facet
* @returns Promise<T>
*/
export const asPromise = <T>(facet: Facet<T>) =>
new Promise<T>((resolve) => {
const value = facet.get()
if (value !== NO_VALUE) {
resolve(value)
return
export const asPromise = <T>(facet: Facet<T>) => {
let resolve: (value: T | PromiseLike<T>) => void = noop

const promise = new Promise<T>((_resolve) => {
resolve = _resolve
})

const value = facet.get()
if (value !== NO_VALUE) {
resolve(value)

return {
promise,
cancel: noop,
}
}

const cleanup = facet.observe((value: T) => {
resolve(value)
const cleanup = facet.observe(resolve)

return {
promise: promise.then((value) => {
cleanup()
})
})
return value
}),
cancel: cleanup,
}
}

const noop = () => {}

0 comments on commit e22975d

Please sign in to comment.