#NextJS App Router - optimize queries

1 messages · Page 1 of 1 (latest)

hearty quarry
#

In a db.transaction where we cannot use batch to reduce round-trips directly with SQL and DrizzleORM in NextJS App Router

  const resultOne = await queryOne(tx, paramOne)
  const resultTwo = await queryTwo(tx, paramTwo)
  const resultThree = await queryThree(tx, paramThree)

We can try to "batch" them with a Promise.all, however, how do we expect to get the correct values in the correct const names if they are parallel and might finish at different times?

Is it easy as

const { resultOne, resultTwo, resultThree } = await Promise.all([queryOne(tx, paramOne), queryTwo(tx, paramTwo), queryThree(tx, paramThree)]

fix my psuedo/guess code

rose roostBOT
#

Hi @hearty quarry. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

Your understanding is correct, and your approach to optimizing the queries using Promise.all is on the right track. However, there's a small adjustment needed in your syntax. Here's the correct way to use Promise.all to parallelize your queries while still assigning the results to specific constants:

const [resultOne, resultTwo, resultThree] = await Promise.all([
  queryOne(tx, paramOne),
  queryTwo(tx, paramTwo),
  queryThree(tx, paramThree)
]);

This approach allows you to run the queries in parallel, potentially reducing the overall execution time, while still assigning each result to its corresponding variable. The order of the results in the array returned by Promise.all corresponds to the order of the promises in the input array, regardless of which promise resolves first.

This pattern is indeed recommended for optimizing data fetching in Next.js, as mentioned in the Next.js documentation on parallel data fetching:

"To fetch data in parallel, you can eagerly initiate requests by defining them outside the components that use the data. This saves time by initiating both requests in parallel, however, the user won't see the rendered result until both promises are resolved."

By using Promise.all, you're ensuring that all queries are initiated simultaneously, which can lead to better performance compared to sequential execution.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@hearty quarry Kapa.ai is still learning and improving, please let me know how I did by reacting below.

hearty quarry
#

@rose roost what if the third query returns an object instead of a singular value would you help refactor our code example

rose roostBOT
#

Let me check the knowledge base for you again. Give me one moment! :books:

#

Certainly! If the third query returns an object instead of a singular value, we can still use Promise.all to parallelize our queries. We just need to adjust how we destructure the results. Here's how we can refactor the code example:

const [resultOne, resultTwo, { propertyA, propertyB }] = await Promise.all([
  queryOne(tx, paramOne),
  queryTwo(tx, paramTwo),
  queryThree(tx, paramThree)
]);

In this refactored version:

  • resultOne and resultTwo remain as they were, assuming they return singular values.
  • For the third query result, we're using object destructuring to extract specific properties (propertyA and propertyB) from the returned object.

If you want to keep the entire object returned by the third query, you can do this instead:

const [resultOne, resultTwo, resultThree] = await Promise.all([
  queryOne(tx, paramOne),
  queryTwo(tx, paramTwo),
  queryThree(tx, paramThree)
]);

// Now resultThree is the entire object returned by queryThree
const { propertyA, propertyB } = resultThree;

This approach aligns with the Next.js best practices for parallel data fetching, as mentioned in the Next.js documentation. It allows you to initiate all queries simultaneously, potentially improving performance by reducing the overall execution time.

Remember, the order of the results in the array returned by Promise.all corresponds to the order of the promises in the input array, regardless of which promise resolves first. This ensures that each result is correctly assigned to its corresponding variable.

#

kapa.ai: Your answer is accurate and helpful. It correctly addresses the user's question about handling a case where the third query returns an object instead of a singular value. The code examples provided demonstrate how to use object destructuring within the Promise.all result array, as well as an alternative approach of keeping the entire object and destructuring it afterwards. This aligns well with Next.js best practices for parallel data fetching. Good job on providing clear, concise explanations and relevant code examples.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@hearty quarry Kapa.ai is still learning and improving, please let me know how I did by reacting below.

hearty quarry
#

@rose roost is this valid or no

const [resultOne, resultTwo, { propertyA, propertyB }] = await Promise.all([
queryOne(tx, paramOne),
queryTwo(tx, paramTwo),
queryThree(tx, paramThree)
]);

rose roostBOT
#

Let me check the knowledge base for you again. Give me one moment! :books:

#

Yes, the code you provided is valid and correct:

const [resultOne, resultTwo, { propertyA, propertyB }] = await Promise.all([
  queryOne(tx, paramOne),
  queryTwo(tx, paramTwo),
  queryThree(tx, paramThree)
]);

This approach is a valid way to use Promise.all for parallel data fetching in Next.js. It allows you to run multiple asynchronous operations concurrently and destructure their results, including nested object properties.

Here's why it's valid:

  1. Promise.all executes all promises in parallel and returns an array of results in the same order as the input promises.
  2. The left side of the assignment uses array destructuring to assign the results to variables.
  3. For the third result, it uses nested object destructuring to directly extract propertyA and propertyB from the object returned by queryThree.

This pattern aligns with Next.js best practices for optimizing data fetching, as described in the Next.js documentation on parallel data fetching. It allows you to initiate multiple data requests simultaneously, potentially reducing the overall loading time of your application.

Remember that while this approach is more efficient than sequential fetching, all promises still need to resolve before the results are available. If you need to show partial results as they become available, you might want to consider using individual await statements with React Suspense boundaries.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: