Repository: getsentry/sentry
Pull request: perf(replay): Improve Replay Details pageload speed by fetching errors in parallel with replay segments
Before we can see that the 3rd request is blocked on the first two:
![before](https://user-images.githubusercontent.com/187460/191842210-b780c2b3-06c9-42b0-b2d6-68877a40661e.png)

After this change the 3rd request is only waiting for the 1st to complete. The segment data download is still happening.
![after](https://user-images.githubusercontent.com/187460/191842223-8e6f0a92-84c9-4340-b719-2387a0439fad.png)

Note: In these screen shots from google chrome the green horizontal bar represents the server-wait time (the time that the server spends getting the data ready) and the blue bars represent the content download time.

Fixes #38341


Problem statement:
Perf: Make data fetching slightly more parallel, start fetching the list of errors as soon as the replay obj is ready
Right now we do this in useReplayData:
```
const [record, attachments] = await Promise.all([
  fetchReplay(),
  fetchAllRRwebEvents(),
]);
const replayRecord = mapResponseToReplayRecord(record);
const errors = await fetchErrors(replayRecord);
```

I think it could be faster if we put the error stuff into the initial promise. Something like this:
```
const [[record, errors], attachments] = await Promise.all([
  async () => {
    const record = await fetchReplay();
    const replayRecord = mapResponseToReplayRecord(record);
    const errors = await fetchErrors(replayRecord);
    return [record, errors];
  },
  fetchAllRRwebEvents(),
]);
```

Task: Need to test the code, and measure perf before/after. 
Measure when network is slow & fast, when replays have many segments, or not that many.
Also check that error handling is still reasonable, and when errors happen (esp multiple errors at the same time, like 404) we see the right message.

Hints from issue discussion:
Related to #38524

Commit message: remove the old code

Patch to review:
diff --git a/static/app/utils/replays/hooks/useReplayData.tsx b/static/app/utils/replays/hooks/useReplayData.tsx
index 2dbf18bcacbc4a..a2d921f313e6cb 100644
--- a/static/app/utils/replays/hooks/useReplayData.tsx
+++ b/static/app/utils/replays/hooks/useReplayData.tsx
@@ -189,12 +189,15 @@ function useReplayData({replaySlug, orgSlug}: Options): Result {
     setState(INITIAL_STATE);
 
     try {
-      const [record, attachments] = await Promise.all([
-        fetchReplay(),
+      const [[replayRecord, errors], attachments] = await Promise.all([
+        (async (): Promise<[ReplayRecord, any]> => {
+          const fetchedRecord = await fetchReplay();
+          const mappedRecord = mapResponseToReplayRecord(fetchedRecord);
+          const fetchedErrors = await fetchErrors(mappedRecord);
+          return [mappedRecord, fetchedErrors];
+        })(),
         fetchAllRRwebEvents(),
       ]);
-      const replayRecord = mapResponseToReplayRecord(record);
-      const errors = await fetchErrors(replayRecord);
 
       setState(prev => ({
         ...prev,


Code review comments:
diff_hunk: @@ -189,12 +189,15 @@ function useReplayData({replaySlug, orgSlug}: Options): Result {
     setState(INITIAL_STATE);
 
     try {
-      const [record, attachments] = await Promise.all([
-        fetchReplay(),
+      const [[replayRecord, errors], attachments] = await Promise.all([
+        (async (): Promise<[ReplayRecord, any]> => {
+          const fetchedRecord = await fetchReplay();
+          const mappedRecord = mapResponseToReplayRecord(fetchedRecord);
+          const fetchedErrors = await fetchErrors(mappedRecord);
+          return [mappedRecord, fetchedErrors];
+        })(),
path: static/app/utils/replays/hooks/useReplayData.tsx
text: @user1:
Imo this is a bit hard to read with nested array destructuring and the iife... what about something like:

```javascript
const replayPromise = fetchReplay();
const attachmentsPromise = fetchAllRRwebEvents();
const fetchedRecord = await replayPromise;
const mappedRecord = mapResponseToReplayRecord(fetchedRecord);
const [errors, attachments] = await Promise.all([fetchErrors(mappedRecord), attachmentsPromise])
```

@author:
it's not my preference to split up promise exec from the await call, i think it makes it easy to have different things mix together, for example i'm not a fan of:
```
const replayPromise = fetchReplay();
... anything can happen! the two parts are not connected enough for me ...
const fetchedRecord = await replayPromise;
```


It'd give the IIFE a name though, then we could do two destructuring's... along the lines of:
```typescript
const fetchReplayAndErrors = async (): Promise<[ReplayRecord, any]> => {
  const fetchedRecord = await fetchReplay();
  const mappedRecord = mapResponseToReplayRecord(fetchedRecord);
  const fetchedErrors = await fetchErrors(mappedRecord);
  return [mappedRecord, fetchedErrors];
});

const [replayAndErrors, attachments] = await Promise.all([fetchReplayAndErrors(), fetchAllRRwebEvents()]);
const [replay, errors] = replayAndErrors;
```