Skip to content

Instantly share code, notes, and snippets.

@hamlim
Created September 27, 2020 23:16
Show Gist options
  • Save hamlim/ddd14f6210600498b398fdbabdafbc25 to your computer and use it in GitHub Desktop.
Save hamlim/ddd14f6210600498b398fdbabdafbc25 to your computer and use it in GitHub Desktop.
type Cache = Map<string, any>
type Loader = (key: string) => Promise<any>
enum Status {
Pending,
Resolved,
Rejected,
}
interface Resource {
status: Status
value: Promise<any>
}
let localCache: Cache = new Map()
// This rest is a basic Suspense cache implementation.
let PENDING = 0
let RESOLVED = 1
let REJECTED = 2
export function createResource(
key: string,
loader: Loader,
cache: Cache = localCache,
) {
if (cache.has(key)) {
let record = cache.get(key)
return record
} else {
let promise = loader(key)
let record = {
status: PENDING,
value: promise,
error: undefined,
}
promise.then(
(value) => {
if (record.status === PENDING) {
record.status = RESOLVED
record.value = value
}
},
(error) => {
if (record.status === PENDING) {
record.status = REJECTED
record.value = error
}
},
)
cache.set(key, record)
return record
}
}
export function read(resource: Resource) {
switch (resource.status) {
case PENDING:
let promise = resource.value
throw promise
case RESOLVED:
let value = resource.value
return value
case REJECTED:
let error = resource.value
throw error
}
}
export function unstable_readCache(
key: string,
loader: Loader,
cache: Cache = localCache,
) {
if (cache.has(key)) {
let record = cache.get(key)
switch (record.status) {
case PENDING:
let promise = record.value
throw promise
case RESOLVED:
let value = record.value
return value
case REJECTED:
let error = record.value
throw error
}
} else {
let promise = loader(key)
let record = {
status: PENDING,
value: promise,
error: undefined,
}
promise.then(
(value) => {
if (record.status === PENDING) {
record.status = RESOLVED
record.value = value
}
},
(error) => {
if (record.status === PENDING) {
record.status = REJECTED
record.value = error
}
},
)
cache.set(key, record)
switch (record.status) {
case PENDING:
throw promise
case RESOLVED:
let value = record.value
return value
case REJECTED:
let error = record.error
throw error
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment