Search code examples
async-awaitpromisefetch

fetch in parallel async/await with Promises.all


I continue to struggle with serial/parallel processing in JS (promises). I want to query my server and identify those queries that take longer than, say 500 ms. The following works, but as far as I understand, the queries are made one after another.

const query = async (queries) => {
    for (let i = 0, j = queries.length; i < j; i++) {
        let t = process.hrtime();
        const response = await fetch(queries[i]);
        const result = await response.json();
        t = process.hrtime(t);
        
        const ms = Math.round((t[0] * 1000) + (t[1] / 1000000));
        if (ms > 500) {
            console.log(ms, queries[i]);
        }
    }
}

query(arrayOfQueries);

// console output below (snipped for brevity)
3085 http://localhost:3010/v3/…
2463 http://localhost:3010/v3/…
2484 http://localhost:3010/v3/…
…

I change the above code to fire the queries in parallel, but now I get back an array of promises. I can't figure out how to identify only those promises that take longer than 500ms to resolve

const query = async (queries) => {
    const r = await Promise.all(queries.map(async (q) => fetch(q)));
    console.log(r);
};

// console output
[
  Response {
    size: 0,
    timeout: 0,
    [Symbol(Body internals)]: { body: [PassThrough], disturbed: false, error: null },
    [Symbol(Response internals)]: {
      url: 'http://localhost:3010/v3/…',
      status: 200,
      statusText: 'OK',
      headers: [Headers],
      counter: 0
    }
  },
  Response {
    size: 0,
    timeout: 0,
    [Symbol(Body internals)]: { body: [PassThrough], disturbed: false, error: null },
    [Symbol(Response internals)]: {
      url: 'http://localhost:3010/v3/…',
      status: 200,
      statusText: 'OK',
      headers: [Headers],
      counter: 0
    }
  },
  Response {
    size: 0,
    timeout: 0,
    [Symbol(Body internals)]: { body: [PassThrough], disturbed: false, error: null },
    [Symbol(Response internals)]: {
      url: 'http://localhost:3010/v3/…',
      status: 200,
      statusText: 'OK',
      headers: [Headers],
      counter: 0
    }
  },

Solution

  • When running the queries in parallel, you would have to add code (similar to what you had for your non-parallel example) to time each one separately so you could track each individual request separately.

    The time of each request overlaps so you can't keep track of the timing of each individual request from the outside. Here's an example of timing each individual request:

    const query = async (queries) => {
        const r = await Promise.all(queries.map(async (q) => {
            const start = Date.now();
            const response = await fetch(q);
            const json = await response.json();
            const delta = Date.now() - start;
            console.log(`${delta}ms for ${q}`);
            return json;
        });
        return r;
    };
    

    This will output the timing for each request at the time it finishes which may not be in the same order that the requests were made. If you want, you can collect these timing results into an array and output all the timing at once at the end.