diff --git a/spec/file_caching_test.js b/spec/file_caching_test.js
index db08ac9b764180ef2db97163e6002434b205c5ec..6c6c0327ef8ee087911dc924ba89eff1e5e9e4bb 100644
--- a/spec/file_caching_test.js
+++ b/spec/file_caching_test.js
@@ -312,4 +312,40 @@ describe('File caching service', function () {
     expect(res2.statusCode).to.equal(200)
     expect(spy.callCount).to.equal(1)
   })
+
+  describe('redis request latency', function () {
+    beforeEach(function () {
+      // overwrite redis.get to simulate network latency
+      const get = redis.client.get
+      redis.client.get = function () {
+        return new Promise(resolve => {
+          setTimeout(async () => {
+            resolve(await get.apply(redis.client, arguments))
+          }, 20)
+        })
+      }
+    })
+
+    it('only requests files once, even though the response takes some time', async function () {
+      let spy
+      mockFetch({
+        'http://ui-server': {
+          '/manifest.json': generateSimpleViteManifest({}),
+          '/example.js': spy = sandbox.spy(() => {
+            return new Response('this is example', { headers: { 'content-type': 'application/javascript' } })
+          })
+        }
+      })
+      app = await mockApp()
+
+      expect(spy.callCount).to.equal(0)
+      const [res1, res2] = await Promise.all([
+        request(app).get('/example.js'),
+        request(app).get('/example.js')
+      ])
+      expect(res1.statusCode).to.equal(200)
+      expect(res2.statusCode).to.equal(200)
+      expect(spy.callCount).to.equal(1)
+    })
+  })
 })
diff --git a/src/cache.js b/src/cache.js
index 1d64904c780082ae633e5df908a9e73b5b617c72..505849c558d29cc8949637a27e162debfeca109e 100644
--- a/src/cache.js
+++ b/src/cache.js
@@ -3,14 +3,6 @@ import * as redis from './redis.js'
 
 const cache = {}
 
-export async function setAsync (key, asyncValue) {
-  logger.trace(`[Cache] Set async ${key}`)
-  cache[key] = asyncValue
-  const value = await asyncValue
-  await set(key, value)
-  return value
-}
-
 export function set (key, value) {
   logger.trace(`[Cache] Set ${key}`)
   if (cache[key] === value) return
@@ -20,28 +12,43 @@ export function set (key, value) {
   }
 }
 
-export async function getBuffer (key) {
-  return get(key, { method: 'getBuffer' })
-}
-
 export async function clear () {
   for (const prop of Object.getOwnPropertyNames(cache)) {
     delete cache[prop]
   }
 }
 
-export async function get (key, { method = 'get' } = {}) {
+export function get (key, fallback) {
   if (cache[key]) {
     logger.trace(`[Cache] Resolve "${key}" from memory`)
     return cache[key]
   }
 
-  if (redis.isEnabled()) {
-    const result = await redis.client[method]?.(key)
-    if (result) {
-      logger.trace(`[Cache] Resolve "${key}" from redis`)
-      cache[key] = result
+  const promise = (async () => {
+    if (redis.isEnabled()) {
+      let result = await redis.client.get(key)
+      if (result) {
+        logger.trace(`[Cache] Resolve "${key}" from redis`)
+        result = JSON.parse(result)
+        cache[key] = result
+        return result
+      }
     }
-    return result
-  }
+
+    if (!fallback) return
+
+    const fallbackResult = await fallback()
+    if (fallbackResult) {
+      logger.trace(`[Cache] Found a fallback for "${key}"`)
+      cache[key] = fallbackResult
+      if (redis.isEnabled()) redis.client.set(key, JSON.stringify(fallbackResult))
+    }
+    return fallbackResult
+  })()
+
+  cache[key] = promise
+
+  return promise
 }
+
+export function getCache () { return cache }
diff --git a/src/files.js b/src/files.js
index 6f1261ed35a1a9720020bee18c72a475c2557587..ff0f20fb060a5cd2fa7cadd21d745c81a2faaa69 100644
--- a/src/files.js
+++ b/src/files.js
@@ -6,6 +6,12 @@ import { getCSSDependenciesFor, getViteManifests } from './manifests.js'
 import * as cache from './cache.js'
 import { logger } from './logger.js'
 import { NotFoundError } from './errors.js'
+import * as redis from './redis.js'
+
+export function createWritable (body) {
+  if (typeof body !== 'string' && !(body instanceof Buffer)) return JSON.stringify(body)
+  return body
+}
 
 export async function fetchFileWithHeadersFromBaseUrl (path, baseUrl, version) {
   const [response, dependencies] = await Promise.all([
@@ -50,22 +56,41 @@ export async function fetchFileWithHeaders ({ path, version }) {
   return Promise.any(config.urls.map(baseUrl => fetchFileWithHeadersFromBaseUrl(path, baseUrl, version)))
 }
 
-export async function saveAsyncToCache ({ version, path, promise }) {
-  await Promise.all([
-    cache.setAsync(getRedisKey({ version, name: `${path}:body` }), promise.then(({ body }) => {
-      if (typeof body !== 'string' && !(body instanceof Buffer)) return JSON.stringify(body)
-      return body
-    })),
-    cache.setAsync(getRedisKey({ version, name: `${path}:meta` }), promise.then(({ body, ...rest }) => JSON.stringify(rest)))
-  ])
-  return promise
-}
+export function getFile ({ version, path }) {
+  const key = getRedisKey({ version, name: `${path}` })
 
-export async function loadFromCache ({ version, path }) {
-  const [body, meta = '{}'] = await Promise.all([
-    cache.getBuffer(getRedisKey({ version, name: `${path}:body` })),
-    cache.get(getRedisKey({ version, name: `${path}:meta` }))
-  ])
-  if (!body) return
-  return { ...JSON.parse(meta), body }
+  // try to get the file synchronously.
+  const data = cache.getCache()[key]
+  if (data) return data
+
+  // if synchronously does not work, store the async promise for further requests
+  const promise = (async () => {
+    const bodyKey = getRedisKey({ version, name: `${path}:body` })
+    const metaKey = getRedisKey({ version, name: `${path}:meta` })
+
+    if (redis.isEnabled()) {
+      const [body, meta = '{}'] = await Promise.all([
+        redis.client.getBuffer(bodyKey),
+        redis.client.get(metaKey)
+      ])
+
+      if (body) {
+        return (cache.getCache()[key] = { body, ...JSON.parse(meta) })
+      }
+    }
+
+    const dataFromServer = await fetchFileWithHeaders({ version, path })
+    if (redis.isEnabled()) {
+      const { body, ...rest } = dataFromServer
+      redis.client.set(bodyKey, createWritable(body))
+      redis.client.set(metaKey, JSON.stringify(rest))
+    }
+
+    // overwrite cache with synchronous data
+    return (cache.getCache()[key] = dataFromServer)
+  })()
+
+  // temporary set to promise
+  cache.getCache()[key] = promise
+  return promise
 }
diff --git a/src/manifests.js b/src/manifests.js
index 94bd2dd406f1ed617acf055b95ef4cff779c2522..7f6ed5da34922fa7336f886f5ff25bd50283c61a 100644
--- a/src/manifests.js
+++ b/src/manifests.js
@@ -28,34 +28,22 @@ export async function fetchViteManifests () {
   return viteManifests.reduce((memo, manifest) => Object.assign(memo, manifest), {})
 }
 
-export async function getViteManifests ({ version }) {
-  let manifests = await cache.get(getRedisKey({ version, name: 'viteManifests' }))
-  if (!manifests) {
-    manifests = await cache.setAsync(getRedisKey({ version, name: 'viteManifests' }), fetchViteManifests().then(m => JSON.stringify(m)))
-  }
-  return JSON.parse(manifests)
+export function getViteManifests ({ version }) {
+  return cache.get(getRedisKey({ version, name: 'viteManifests' }), () => fetchViteManifests())
 }
 
-export async function getOxManifests ({ version }) {
-  let manifests = await cache.get(getRedisKey({ version, name: 'oxManifests' }))
-  if (!manifests) {
-    manifests = await cache.setAsync(getRedisKey({ version, name: 'oxManifests' }), (async () => {
-      const viteManifests = await getViteManifests({ version })
-      return JSON.stringify(viteToOxManifest(viteManifests))
-    })())
-  }
-  return JSON.parse(manifests)
+export function getOxManifests ({ version }) {
+  return cache.get(getRedisKey({ version, name: 'oxManifests' }), async () => {
+    const viteManifests = await getViteManifests({ version })
+    return viteToOxManifest(viteManifests)
+  })
 }
 
-export async function getDependencies ({ version }) {
-  let deps = await cache.get(getRedisKey({ version, name: 'dependencies' }))
-  if (!deps) {
-    deps = await await cache.setAsync(getRedisKey({ version, name: 'dependencies' }), (async () => {
-      const viteManifests = await getViteManifests({ version })
-      return JSON.stringify(viteManifestToDeps(viteManifests))
-    })())
-  }
-  return JSON.parse(deps)
+export function getDependencies ({ version }) {
+  return cache.get(getRedisKey({ version, name: 'dependencies' }), async () => {
+    const viteManifests = await getViteManifests({ version })
+    return viteManifestToDeps(viteManifests)
+  })
 }
 
 export async function getCSSDependenciesFor ({ file, version }) {
diff --git a/src/meta.js b/src/meta.js
index 0b99feb499c7b3f6e904242e1d7ba5d388f162d0..386c78b3cacae2a06decc1b9977871e68e120d67 100644
--- a/src/meta.js
+++ b/src/meta.js
@@ -27,10 +27,6 @@ export async function fetchMergedMetadata () {
   return metadata.filter(Boolean)
 }
 
-export async function getMergedMetadata ({ version }) {
-  let metadata = await cache.get(getRedisKey({ version, name: 'mergedMetadata' }))
-  if (!metadata) {
-    metadata = await cache.setAsync(getRedisKey({ version, name: 'mergedMetadata' }), fetchMergedMetadata().then(m => JSON.stringify(m)))
-  }
-  return JSON.parse(metadata)
+export function getMergedMetadata ({ version }) {
+  return cache.get(getRedisKey({ version, name: 'mergedMetadata' }), () => fetchMergedMetadata())
 }
diff --git a/src/middlewares/serve-files.js b/src/middlewares/serve-files.js
index 9f1724569417dcf569010772fbe56454224c15f0..1ef2cb4cde7f63d6310e9c64ef3829c2d903a3f8 100644
--- a/src/middlewares/serve-files.js
+++ b/src/middlewares/serve-files.js
@@ -1,4 +1,4 @@
-import { fetchFileWithHeaders, loadFromCache, saveAsyncToCache } from '../files.js'
+import { getFile } from '../files.js'
 import { NotFoundError } from '../errors.js'
 import createError from 'http-errors'
 
@@ -7,15 +7,8 @@ export default async function (req, res, next) {
     if (req.method !== 'GET') return next()
     const version = res.version
     const path = req.path === '/' ? '/index.html' : req.path
-    let data = await loadFromCache({
-      path,
-      version
-    })
-    if (!data) {
-      data = await saveAsyncToCache({ version, path, promise: fetchFileWithHeaders({ path, version }) })
-    }
+    const { body, headers, sha256Sum } = await getFile({ version, path })
 
-    const { body, headers, sha256Sum } = data
     res.set(headers)
     res.locals.sha256Sum = sha256Sum
     res.send(body)