Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

How can I combine sequential and concurrent work in one async function?

Quick answer

Await each prerequisite before starting work that depends on it. Once you have the shared input, start independent operations together with Promise.all(), then await that group before the final step that needs their results. Put a try/catch around the boundary where you want to handle failures. A failure does not by itself cancel sibling work, so use cancellation only when the operations support it.

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

I have an async workflow with setup, two independent requests, and then a final save. How do I mix sequential and concurrent steps without making the order confusing?

Geez

Make the dependencies visible in the order of the code: await setup first; start the independent requests together; await both results; then do the save. Only the middle operations run concurrently, and only if neither needs the other's result. Microsoft’s Azure Functions guidance recommends Promise.all() for independent asynchronous operations and illustrates awaiting prerequisite data before starting operations that use it [S1].

Here’s a plain JavaScript example. Assume the functions shown already exist and return promises; their implementations and failure policy depend on your app:

async function buildReport(accountId) {
  try {
    // Sequential prerequisite: later work needs this account data.
    const account = await loadAccount(accountId);

    // Both tasks use account, but neither uses the other's result.
    const [orders, preferences] = await Promise.all([
      loadOrders(account.id),
      loadPreferences(account.id),
    ]);

    // Dependent completion: needs both concurrent results.
    return await saveReport({ account, orders, preferences });
  } catch (error) {
    // Handle here, or rethrow for the caller to handle.
    throw error;
  }
}

The try/catch marks one possible boundary, not a required policy. Replace the rethrow with the handling your app needs, or let the caller own the catch. Use Promise.all() here because the middle tasks are independent; it does not make dependent tasks safe to run together [S1].

Follow-up question

How can I tell whether two operations are actually safe to put in Promise.all()?

Geez

Ask whether either operation needs the other’s output, or whether their order changes the result. If one needs the other’s result, keep that dependency sequential. If both only need the completed setup value and can proceed without coordinating, they are candidates for the concurrent group.

For example, loading orders and loading preferences both use account.id; neither receives the other’s result. But if preferences must use a value returned by the orders request, await the orders first, then start the preferences request. A simple dependency sketch helps: account → orders and account → preferences can branch; orders → preferences means there is another dependency to respect.

Follow-up question

What should I expect if one of the concurrent operations fails? Does the other one stop too?

Geez

Choose deliberately what the workflow should do when a task in the group fails: fail the overall operation, report an error, or use a different strategy if partial results are acceptable. Microsoft recommends proper error handling but does not prescribe one universal failure policy [S1].

A failure does not automatically cancel sibling work. Cancellation is relevant only when the operations accept and honor an abort signal. The Azure SDK documentation describes passing such a signal to supported operations and aborting later; it does not claim that a failure automatically cancels other tasks [S2]. If your functions do not support cancellation, handle the group’s failure without assuming the other operation has stopped.

Follow-up question

Where should I put the try/catch if a caller also needs to know whether the workflow failed?

Geez

Put the catch where you have enough context to make the intended decision. If this function should handle the failure locally, perform that handling in its catch. If the caller should decide what happens, rethrow the error, as in the example. Avoid catching an error only to ignore it; make the chosen boundary clear to whoever calls the function.

The example uses a catch around the whole workflow, so it covers setup, the concurrent group, and the final save. You could instead put handling around a narrower step if only that step has a distinct policy. Whatever boundary you choose, keep the prerequisite, independent group, and dependent completion in their dependency order.

A practical checklist

  • List each operation and the inputs it needs.

  • Await prerequisites before starting work that depends on their results.

  • Put only mutually independent tasks in the Promise.all() group.

  • Await the group before running a step that needs its results.

  • Choose where failures are handled; do not assume a failure cancels sibling work.

A few more useful answers

Should I use `Promise.all()` for tasks that can partially succeed?

Use it when the workflow should treat the group as a unit and proceed only after the group completes successfully. If partial results are acceptable, choose and implement a deliberate result-handling strategy; the cited guidance does not prescribe one.

Can I put the final dependent step in the same `Promise.all()` group?

Not if it needs results from the other tasks in that group. Await those results first, then call and await the dependent step.

Does adding an abort signal automatically stop every task in the group?

No. Cancellation is relevant only for operations that accept and honor the signal, and failure alone does not cancel sibling work [S2].

Sources

References used for this guide.

  1. [S1] Optimize performance and scaling for Node.js Azure Functions
    learn.microsoft.com · Checked
  2. [S2] Azure Abort Controller for JavaScript, version 2.2.0
    learn.microsoft.com · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work