refactor(pwa): ♻️ transform fetch Strategy into static only class
This commit is contained in:
parent
67e3330587
commit
96a4199fa2
|
|
@ -1,15 +1,21 @@
|
|||
export class Strategy {
|
||||
#cache: Cache
|
||||
|
||||
constructor(cache: Cache) {
|
||||
this.#cache = cache
|
||||
private constructor() {
|
||||
throw new Error(
|
||||
'fetch Strategy is not instantiable and only expose static methods',
|
||||
)
|
||||
}
|
||||
|
||||
cacheFirst({ request, preloadResponse }: Pick<FetchEvent, 'request' | 'preloadResponse'>) {
|
||||
static cacheFirst(
|
||||
cache: Cache,
|
||||
{ request, preloadResponse }: Pick<
|
||||
FetchEvent,
|
||||
'request' | 'preloadResponse'
|
||||
>,
|
||||
) {
|
||||
const fetchRequest = async () => {
|
||||
const response = await fetch(request)
|
||||
if (response.ok) {
|
||||
this.#cache.put(request, response)
|
||||
cache.put(request, response)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -17,22 +23,26 @@ export class Strategy {
|
|||
preloadResponse
|
||||
.then((preload: Response | undefined) => {
|
||||
if (preload?.ok) {
|
||||
return this.#cache.put(request, preload)
|
||||
return cache.put(request, preload)
|
||||
}
|
||||
throw new Error()
|
||||
})
|
||||
// Else fetch request
|
||||
.catch(fetchRequest)
|
||||
|
||||
return this.#cache.match(request)
|
||||
return cache.match(request)
|
||||
}
|
||||
|
||||
fastestAndCacheRefresh(
|
||||
{ request, preloadResponse }: Pick<FetchEvent, 'request' | 'preloadResponse'>,
|
||||
ac: AbortController = new AbortController()
|
||||
static fastestAndCacheRefresh(
|
||||
cache: Cache,
|
||||
{ request, preloadResponse }: Pick<
|
||||
FetchEvent,
|
||||
'request' | 'preloadResponse'
|
||||
>,
|
||||
ac: AbortController = new AbortController(),
|
||||
) {
|
||||
// Get cache or throw
|
||||
const cachedOrError = this.#cache.match(request)
|
||||
const cachedOrError = cache.match(request)
|
||||
.then((response) => {
|
||||
if (response) {
|
||||
// Abort network request
|
||||
|
|
@ -43,12 +53,12 @@ export class Strategy {
|
|||
})
|
||||
|
||||
// Fetch and cache
|
||||
const fetchedAndCached = this.networkOnly({ request, preloadResponse}, ac)
|
||||
const fetchedAndCached = this.networkOnly({ request, preloadResponse }, ac)
|
||||
.then((response) => {
|
||||
// Abort cache request
|
||||
ac.abort()
|
||||
// Update cache
|
||||
this.#cache.put(request, response.clone())
|
||||
cache.put(request, response.clone())
|
||||
return response
|
||||
})
|
||||
|
||||
|
|
@ -56,8 +66,12 @@ export class Strategy {
|
|||
return Promise.race([cachedOrError, fetchedAndCached])
|
||||
}
|
||||
|
||||
async networkFirst(
|
||||
{ request, preloadResponse }: Pick<FetchEvent, 'request' | 'preloadResponse'>,
|
||||
static async networkFirst(
|
||||
cache: Cache,
|
||||
{ request, preloadResponse }: Pick<
|
||||
FetchEvent,
|
||||
'request' | 'preloadResponse'
|
||||
>,
|
||||
{ fallbackUrl, timeout }: { fallbackUrl?: string; timeout?: number },
|
||||
) {
|
||||
const signal = timeout ? AbortSignal.timeout(timeout) : undefined
|
||||
|
|
@ -66,7 +80,7 @@ export class Strategy {
|
|||
// Get navigator preload (see: https://developer.mozilla.org/en-US/docs/Web/API/Pick<FetchEvent, 'request' | 'preloadResponse'>/preloadResponse)
|
||||
const preload = await getPreload(preloadResponse)
|
||||
if (preload?.ok) {
|
||||
this.#cache.put(request, preload.clone())
|
||||
cache.put(request, preload.clone())
|
||||
return preload
|
||||
}
|
||||
} catch {
|
||||
|
|
@ -74,23 +88,26 @@ export class Strategy {
|
|||
// Else fetch request
|
||||
const response = await fetch(request, { signal })
|
||||
if (response.ok) {
|
||||
this.#cache.put(request, response.clone())
|
||||
cache.put(request, response.clone())
|
||||
return response
|
||||
}
|
||||
} catch {
|
||||
// Else return fallback or cached response
|
||||
return this.#cache.match(fallbackUrl ?? request)
|
||||
return cache.match(fallbackUrl ?? request)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
networkOnly(
|
||||
{ request, preloadResponse }: Pick<FetchEvent, 'request' | 'preloadResponse'>,
|
||||
ac: AbortController = new AbortController()
|
||||
static networkOnly(
|
||||
{ request, preloadResponse }: Pick<
|
||||
FetchEvent,
|
||||
'request' | 'preloadResponse'
|
||||
>,
|
||||
ac: AbortController = new AbortController(),
|
||||
): Promise<Response> {
|
||||
// Browser preload
|
||||
const preload = getPreload(preloadResponse, ac)
|
||||
.then(response => {
|
||||
.then((response) => {
|
||||
if (response === undefined) {
|
||||
throw new Error(`no preload response for ${request.url}`)
|
||||
}
|
||||
|
|
@ -101,13 +118,13 @@ export class Strategy {
|
|||
|
||||
// Client fetch
|
||||
const fetched = fetch(request, { signal: ac.signal })
|
||||
.then(response => {
|
||||
.then((response) => {
|
||||
// Cancel preload event
|
||||
ac.abort()
|
||||
return response
|
||||
})
|
||||
|
||||
return Promise.race([preload, fetched])
|
||||
|
||||
return Promise.race([preload, fetched])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue