Loading KV keys asynchronously from workers

I am trying to load multiple KV values from Workers asynchronously, but this has led to high latency and a long runtime. Runtime seems to increase linearly with the number of KV keys queried

let keys = [key1, key2, ... ]
let kvValues = [];
for (const key of keys) {
    var val = KV.get(key, "text");
    kvValues.push(val);
  }
kvValues = await Promise.all(kvValues); //12-13ms per key
kvValues.map(item => some_function); //<1ms

Can KV data be loaded asynchronously from Workers? So far, I have not found any conclusive answers on this. Help is much appreciated!

Create an async function then using

event.waitUntil(await fun());

should work, note that only 50 put requests, per worker event.

1 Like

Thanks very much for taking the time to respond!

My understanding is that

event.waitUntil() is only useful if you have some asynchronous task that you want to keep running after returning a response to the visitor

Since I’m making get requests that need to be processed before a response is sent back to the user (not put requests), how would event.waitUntil help?

Thanks again for taking the time to respond!

Make sure that the object you’re sending to the array is actually a promise and not an object with a wrapped promise. Since Promise.all will only be async when it’s resolving promises.

Asynchronous does not mean Parallel.
Asynchronous means you waste less time than Synchronous.
JavaScript is still Single Threaded.
You cannot divide the time by 10 just by making 10 Asynchronous calls.
If you need to parallelize things, Think about doing your work on client-side workers.
Or making multiple calls to Cloudflare Workers.
Or just storing your data together (colocate them in a NoSQL logic, event if it means duplication)

It’s fully possible to make parallel requests in workers to make 50 calls take the same time as 1 call.

Just need to write it properly, something like this should work:

  const requestAll = Promise.all(servers.map(
    serverUrl => new Promise(async (resolve, reject) => {
      const fetchPromise = fetch(`https://${serverUrl}/`);
      const timeoutPromise = new Promise(resolve => setTimeout(resolve, 2000));
      const response = await Promise.race([fetchPromise, timeoutPromise]);
      if (!response) {
        console.log('Logging failed: Timeout');
        reject('Timeout');
      }
      const { status } = response;
      if (status === 200) {
        const responseText = await response.text();
        resolve(responseText);
      } else {
        reject(status)
      }
    }),
  ));

Example uses race, to handle timeouts and even though map returns promises, this wraps another promise so that we can use resolve and reject to parse the response directly.