Description
How would the enhancement work?
Reduce the number of times that the OptimizelyConfig
's instantiation iterates over the datafile's feature flag list.
Current State Summary
- The OptimizelyConfig instance iterates over each feature flag in a datafile when the constructor calls
OptimizelyConfig.getFeaturesMap
- getDeliveryRules is called during each iteration, which in turn calls getVariableIdMap
getVariableIdMap
iterates over each feature flag and each feature flag's variables
That is, each feature flag iteration in getFeaturesMap
incurs another complete iteration of the feature flags when creating the variablesIdMap
.
Due to the nested loop, creating an OptimizelyConfig
instance with a hypothetical datafile containing 100 feature flags iterates over the entire feature flag list over 10,000 times.
👈 For reference, here's the complete logic flow
1. Constructor calls OptimizelyConfig.getFeaturesMap
2. getFeaturesMap
iterates over each feature flag
javascript-sdk/packages/optimizely-sdk/lib/core/optimizely_config/index.ts
Lines 399 to 405 in 2580ea0
3. OptimizelyConfig.getDeliveryRules
is called during each feature flag iteration
javascript-sdk/packages/optimizely-sdk/lib/core/optimizely_config/index.ts
Lines 425 to 427 in 2580ea0
4. getDeliveryRules
calls OptimizelyConfig.getVariableIdMap
5. getVariableIdMap
iterates over all of the feature flags again & each of the feature flag's variables
javascript-sdk/packages/optimizely-sdk/lib/core/optimizely_config/index.ts
Lines 281 to 291 in 2580ea0
Proposed State
My familiarity with the optimizely-sdk's internals is limited. Based on this narrow understanding, I see a couple of ways to reduce the number of times that the OptimizelyConfig
iterates over the feature flag list.
👈 One option - Create a single variablesIdMap in the constructor
The constructor iterates over the features flags to generate the featureIdVariablesMap
. This reducer's callback could be extended to simultaneously create a single variablesIdMap
. The variablesIdMap
can then be passed to the getFeaturesMap call, considerably reduceing the variablesIdMap
function's overhead.
👈 Another option - Use the featureVariableIdMap to pass a specific feature's variables directly to getVariableIdMap
As getDeliveryRules
has both the featureVariableIdMap
and featureId
, the feature's variables can be passed directly to getVariableIdMap
. This removes the need to iterate over the entire feature flag list.
javascript-sdk/packages/optimizely-sdk/lib/core/optimizely_config/index.ts
Lines 301 to 304 in 2580ea0
This enhancement might look something like,
static getDeliveryRules(
configObj: ProjectConfig,
featureVariableIdMap: FeatureVariablesMap,
featureId: string,
experiments: Experiment[]
): OptimizelyExperiment[] {
// Call `getVariableIdMap` with `featureVariableIdMap[featureId]`, an array of the feature's variables
const variableIdMap = OptimizelyConfig.getVariableIdMap(featureVariableIdMap[featureId]);
static getVariableIdMap(featureVariables: FeatureVariable[]): { [id: string]: FeatureVariable } {
let variablesIdMap: { [id: string]: FeatureVariable } = {};
// Iterate over the `featureVariables` rather than the entire datafile's feature flag list
variablesIdMap = (featureVariables || []).reduce((resultMap: { [id: string]: FeatureVariable }, variable) => {
resultMap[variable.id] = variable;
return resultMap;
}, {});
return variablesIdMap;
}
When would the enhancement be useful?
This is a useful performance enhancement for all @optimizely/javascript-sdk users, but particularly those with a large number of feature flags in their datafile.