diff --git a/packages/core/src/sdk/EventMappers/utils/deepClone.ts b/packages/core/src/sdk/EventMappers/utils/deepClone.ts index 45c6cfce0..44957d9aa 100644 --- a/packages/core/src/sdk/EventMappers/utils/deepClone.ts +++ b/packages/core/src/sdk/EventMappers/utils/deepClone.ts @@ -4,31 +4,42 @@ * Copyright 2016-Present Datadog, Inc. */ -const isDate = (object: unknown): object is Date => { - const type = {}.toString.call(object).slice(8, -1); +const isDate = (type: string, object: unknown): object is Date => { return type === 'Date'; }; -const isArray = (object: unknown): object is unknown[] => { - const type = {}.toString.call(object).slice(8, -1); +const isArray = (type: string, object: unknown): object is unknown[] => { return type === 'Array'; }; -const isObject = (object: unknown): object is Record => { - const type = {}.toString.call(object).slice(8, -1); +const isObject = ( + type: string, + object: unknown +): object is Record => { return type === 'Object'; }; -const isSet = (object: unknown): object is Set => { - const type = {}.toString.call(object).slice(8, -1); +const isSet = (type: string, object: unknown): object is Set => { return type === 'Set'; }; -const isMap = (object: unknown): object is Map => { - const type = {}.toString.call(object).slice(8, -1); +const isMap = ( + type: string, + object: unknown +): object is Map => { return type === 'Map'; }; +/** + * Be careful when changing this value, it can lead to performance issues: https://github.com/DataDog/dd-sdk-reactnative/issues/514. + * Benchmark of average execution time for an action event mapper with different max depth on iOS simulator: + * 7: 40ms + * 6: 15ms + * 5: 4ms + * 4: <1ms + */ +const MAX_DEPTH = 4; + /** * Simple deep clone inspired from https://github.com/angus-c/just/blob/master/packages/collection-clone/index.cjs * Functions and RegExp will be returned as they are. @@ -39,21 +50,22 @@ const isMap = (object: unknown): object is Map => { * @returns */ export const deepClone = (originalObject: T, depth: number = 0): T => { - if (isDate(originalObject)) { + const type = {}.toString.call(originalObject).slice(8, -1); + if (isDate(type, originalObject)) { return (new Date(originalObject.getTime()) as unknown) as T; } - if (isSet(originalObject)) { + if (isSet(type, originalObject)) { return (new Set( [...originalObject].map(value => deepClone(value)) ) as unknown) as T; } - if (isMap(originalObject)) { + if (isMap(type, originalObject)) { return (new Map( [...originalObject].map(kv => [deepClone(kv[0]), deepClone(kv[1])]) ) as unknown) as T; } - if (isArray(originalObject)) { - if (depth >= 7) { + if (isArray(type, originalObject)) { + if (depth >= MAX_DEPTH) { // Break the circular reference here return originalObject; } @@ -66,8 +78,8 @@ export const deepClone = (originalObject: T, depth: number = 0): T => { return (result as unknown) as T; } - if (isObject(originalObject)) { - if (depth >= 7) { + if (isObject(type, originalObject)) { + if (depth >= MAX_DEPTH) { // Break the circular reference here return originalObject; }