@@ -100,63 +100,64 @@ async function getItem(key: string): Promise<GetItemResult> {
100100 }
101101}
102102
103- // Requests an URL and retrieves it from the cache if possible
104- export async function cachedFetch ( request : Request ) : Promise < Response > {
105- let { url } = request
103+ // Handles the case of no-data-yet-cached
104+ async function handleInitialFetch ( args : { request : Request , key : string } ) {
105+ let { request , key } = args
106106
107- let cachePolicyRequest = requestForCachePolicy ( request )
107+ debug && console . log ( `fetch( ${ request . url } ): no policy cached; fetching` )
108108
109- let key = `urlcache:${ url } `
110- let { response : oldResponse , policy : oldPolicy } = await getItem ( key )
109+ // I explicitly want errors here to propagate. Why? Bundled data will have
110+ // an expired policy stored, so it won't hit this branch. Thus, the only
111+ // requests in here will have nothing to fall back to, so we need some way
112+ // to signal that an error happened.
113+ let response = await fetch ( request )
111114
112- if ( process . env . NODE_ENV === 'development' ) {
113- let bundledResponse = await AsyncStorage . getItem ( `${ ROOT } :${ key } :bundled` )
114- if ( bundledResponse ) {
115- debug &&
116- console . log (
117- `fetch(${ request . url } ): in dev mode; returning bundled data` ,
118- )
119- let { body, ...init } = JSON . parse ( bundledResponse )
120- return new Response ( body , init )
121- }
122- }
115+ let cachePolicyRequest = requestForCachePolicy ( request )
116+ let cachePolicyResponse = responseForCachePolicy ( response )
123117
124- // If nothing has ever been cached, go fetch it
125- if ( ! oldPolicy ) {
126- debug && console . log ( `fetch(${ request . url } ): no policy cached; fetching` )
118+ let policy = new CachePolicy ( cachePolicyRequest , cachePolicyResponse )
127119
128- let response = await fetch ( request )
129- let cachePolicyResponse = responseForCachePolicy ( response )
120+ if ( policy . storable ( ) ) {
121+ debug && console . log ( `fetch(${ request . url } ): caching` )
122+ await cacheItem ( { key, response, policy} )
123+ } else {
124+ debug && console . log ( `fetch(${ request . url } ): not cachable` )
125+ }
130126
131- let policy = new CachePolicy ( cachePolicyRequest , cachePolicyResponse )
127+ return response
128+ }
132129
133- if ( policy . storable ( ) ) {
134- debug && console . log ( `fetch( ${ request . url } ): caching` )
135- await cacheItem ( { key , response , policy } )
136- } else {
137- debug && console . log ( `fetch( ${ request . url } ): not cachable` )
138- }
130+ type HandlePartialFetchArgs = {
131+ request : Request ,
132+ oldResponse : Response ,
133+ oldPolicy : CachePolicy ,
134+ key : string ,
135+ }
139136
140- return response
141- }
137+ // Handles the case of cached-and-fresh data
138+ function handleCachedButStillFresh ( args : HandlePartialFetchArgs ) {
139+ let { request, oldResponse, oldPolicy} = args
142140
143- // If we can re-use the cached data, return it; otherwise, we're serving requests from the cache
144- if ( oldPolicy . satisfiesWithoutRevalidation ( cachePolicyRequest ) ) {
145- debug && console . log ( `fetch(${ request . url } ): fresh; returning` )
146- oldResponse . headers = new Headers ( oldPolicy . responseHeaders ( ) )
147- return oldResponse
148- }
141+ debug && console . log ( `fetch(${ request . url } ): fresh; returning` )
142+ oldResponse . headers = new Headers ( oldPolicy . responseHeaders ( ) )
143+ return oldResponse
144+ }
149145
150- // Update the request to ask the origin server if the cached response can be used
151- request . headers = new Headers (
152- oldPolicy . revalidationHeaders ( cachePolicyRequest ) ,
153- )
146+ // Handles the case of cached-but-stale data
147+ async function handleStale ( args : HandlePartialFetchArgs ) {
148+ let { request, oldResponse, oldPolicy, key} = args
154149
155150 debug && console . log ( `fetch(${ request . url } ): stale; validating` )
156151
152+ let cachePolicyRequest = requestForCachePolicy ( request )
153+
157154 let newResponse = null
158155 try {
159- // Send request to the origin server. The server may respond with status 304
156+ // Update the request to ask the origin server if the cached response can be used
157+ let newHeaders = oldPolicy . revalidationHeaders ( cachePolicyRequest )
158+ request . headers = new Headers ( newHeaders )
159+
160+ // Send request to the origin server. The server may respond with status 304.
160161 newResponse = await fetch ( request )
161162 } catch ( error ) {
162163 // "A fetch() promise only rejects when a network error is encountered [...] not on HTTP errors such as 404"
@@ -200,3 +201,39 @@ export async function cachedFetch(request: Request): Promise<Response> {
200201
201202 return response
202203}
204+
205+ // Returns the bundled response when in development
206+ function handleBundledInDev ( request : Request , bundledResponse : string ) {
207+ debug &&
208+ console . log ( `fetch(${ request . url } ): in dev mode; returning bundled data` )
209+ let { body, ...init } = JSON . parse ( bundledResponse )
210+ return new Response ( body , init )
211+ }
212+
213+ // Requests an URL and retrieves it from the cache if possible
214+ export async function cachedFetch ( request : Request ) : Promise < Response > {
215+ let { url} = request
216+
217+ let key = `urlcache:${ url } `
218+ let { response : oldResponse , policy : oldPolicy } = await getItem ( key )
219+
220+ // If we're in dev, and there's bundled data, return it
221+ if ( process . env . NODE_ENV === 'development' ) {
222+ let bundledResponse = await AsyncStorage . getItem ( `${ ROOT } :${ key } :bundled` )
223+ if ( bundledResponse ) {
224+ return handleBundledInDev ( request , bundledResponse )
225+ }
226+ }
227+
228+ // If nothing has ever been cached, go fetch it
229+ if ( ! oldPolicy ) {
230+ return handleInitialFetch ( { request, key} )
231+ }
232+
233+ // If we can re-use the cached data, return it; otherwise, we're serving requests from the cache
234+ if ( oldPolicy . satisfiesWithoutRevalidation ( requestForCachePolicy ( request ) ) ) {
235+ return handleCachedButStillFresh ( { request, oldResponse, oldPolicy, key} )
236+ }
237+
238+ return handleStale ( { request, oldResponse, oldPolicy, key} )
239+ }
0 commit comments