Skip to content

[Performance] Simplify getAllReportErrors and improve its performance  #47691

Description

@OlimpiaZurek

Problem

The current implementation of getAllReportErrors function faces few performance and optimization issues. It uses the reduce method to accumulate errors, which can be less efficient, especially for large datasets. Additionally, combining error objects with object spread syntax introduces unnecessary overhead, potentially slowing down the function.

Similarly, the hasSmartscanError function has complex logic with nested conditions, leading to potential performance bottlenecks.

Solution

Refactor the getAllReportErrors, replacing complex methods with more efficient alternatives. Replacing reduce method with a for...of loop will improve performance, especially for large datasets. Additionally, the use of Object. assign instead of object spread syntax seems more efficient and may reduce memory usage

Additionally, adding early returns and simplify condition checks in hasSmartscanError should improve efficiency of getAllReportErrors.

 function getAllReportErrors(report: OnyxEntry<Report>, reportActions: OnyxEntry<ReportActions>): OnyxCommon.Errors {
     const reportErrors = report?.errors ?? {};
     const reportErrorFields = report?.errorFields ?? {};
-    const reportActionErrors: OnyxCommon.ErrorFields = Object.values(reportActions ?? {}).reduce((prevReportActionErrors, action) => {
-        if (!action || isEmptyObject(action.errors)) {
-            return prevReportActionErrors;
-        }
+    const reportActionsArray = Object.values(reportActions ?? {});
+    const reportActionErrors: OnyxCommon.ErrorFields = {};
 
-        return Object.assign(prevReportActionErrors, action.errors);
-    }, {});
+    for (const action of reportActionsArray) {
+        if (action && !isEmptyObject(action.errors)) {
+            Object.assign(reportActionErrors, action.errors);
+        }
+    }
     const parentReportAction: OnyxEntry<ReportAction> =
         !report?.parentReportID || !report?.parentReportActionID ? undefined : allReportActions?.[report.parentReportID ?? '-1']?.[report.parentReportActionID ?? '-1'];
 
@@ -543,24 +544,22 @@ function getAllReportErrors(report: OnyxEntry<Report>, reportActions: OnyxEntry<
         if (ReportUtils.shouldShowRBRForMissingSmartscanFields(report?.reportID ?? '-1') && !ReportUtils.isSettled(report?.reportID)) {
             reportActionErrors.smartscan = ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericSmartscanFailureMessage');
         }
-    } else if (ReportUtils.hasSmartscanError(Object.values(reportActions ?? {}))) {
+    } else if (ReportUtils.hasSmartscanError(reportActionsArray)) {
         reportActionErrors.smartscan = ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericSmartscanFailureMessage');
     }
     // All error objects related to the report. Each object in the sources contains error messages keyed by microtime
-    const errorSources = {
-        reportErrors,
-        ...reportErrorFields,
-        ...reportActionErrors,
-    };
-    // Combine all error messages keyed by microtime into one object
-    const allReportErrors = Object.values(errorSources)?.reduce((prevReportErrors, errors) => {
-        if (isEmptyObject(errors)) {
-            return prevReportErrors;
-        }
+    // eslint-disable-next-line prefer-object-spread
+    const errorSources = Object.assign({}, reportErrors, reportErrorFields, reportActionErrors);
 
-        return Object.assign(prevReportErrors, errors);
-    }, {});
+    // Combine all error messages keyed by microtime into one object
+    const errorSourcesArray = Object.values(errorSources ?? {});
+    const allReportErrors = {};
 
+    for (const errors of errorSourcesArray) {
+        if (!isEmptyObject(errors)) {
+            Object.assign(allReportErrors, errors);
+        }
+    }
     return allReportErrors;
 }
 function hasSmartscanError(reportActions: ReportAction[]) {
     return reportActions.some((action) => {
-        if (!ReportActionsUtils.isSplitBillAction(action) && !ReportActionsUtils.isReportPreviewAction(action)) {
+        const isReportPreview = ReportActionsUtils.isReportPreviewAction(action);
+        const isSplitReportAction = ReportActionsUtils.isSplitBillAction(action);
+        if (!isSplitReportAction && !isReportPreview) {
             return false;
         }
         const IOUReportID = ReportActionsUtils.getIOUReportIDFromReportActionPreview(action);
eportID) && !isSettled(IOUReportID);
D);
+        if (isReportPreviewError) {
+            return true;
+        }
+
ansactionID ?? '-1' : '-1';
         const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? {};
ion as Transaction);
+        const isSplitBillError = isSplitReportAction && TransactionUtils.hasMissingSmartscanFields(transaction as Transaction);
 
-        return isReportPreviewError || isSplitBillError;
+        return isSplitBillError;
     });
 }

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions