Skip to content

Commit fd10fea

Browse files
committed
Fix the test of E/App tests
1 parent e423194 commit fd10fea

File tree

1 file changed

+23
-33
lines changed

1 file changed

+23
-33
lines changed

lib/OnyxUtils.ts

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ type OnyxMethod = ValueOf<typeof METHOD>;
7676
let mergeQueue: Record<OnyxKey, Array<OnyxValue<OnyxKey>>> = {};
7777
let mergeQueuePromise: Record<OnyxKey, Promise<void>> = {};
7878

79+
// Used to schedule subscriber update to the macro task queue
80+
let nextMacrotaskPromise: Promise<void> | null = null;
81+
7982
// Holds a mapping of all the React components that want their state subscribed to a store key
8083
let callbackToStateMapping: Record<string, CallbackToStateMapping<OnyxKey>> = {};
8184

@@ -85,9 +88,6 @@ let onyxCollectionKeySet = new Set<OnyxKey>();
8588
// Holds a mapping of the connected key to the subscriptionID for faster lookups
8689
let onyxKeyToSubscriptionIDs = new Map();
8790

88-
// Keys with subscriptions currently being established
89-
const pendingSubscriptionKeys = new Set<OnyxKey>();
90-
9191
// Optional user-provided key value states set when Onyx initializes or clears
9292
let defaultKeyStates: Record<OnyxKey, OnyxValue<OnyxKey>> = {};
9393

@@ -804,29 +804,21 @@ function getCollectionDataAndSendAsObject<TKey extends OnyxKey>(matchingKeys: Co
804804
});
805805
}
806806

807-
/** Helps to schedule subscriber update. Schedule the macrotask if the key subscription is in progress to avoid race condition.
807+
/**
808+
* Delays promise resolution until the next macrotask to prevent race condition if the key subscription is in progress.
808809
*
809-
* @param key Onyx key
810810
* @param callback The keyChanged/keysChanged callback
811811
* */
812-
function prepareSubscriberUpdate<TKey extends OnyxKey>(key: TKey, callback: () => void): Promise<void> {
813-
let collectionKey: string | undefined;
814-
try {
815-
collectionKey = getCollectionKey(key);
816-
} catch (e) {
817-
// If getCollectionKey() throws an error it means the key is not a collection key.
818-
collectionKey = undefined;
819-
}
820-
821-
// If subscription is in progress, schedule a macrotask to prevent race condition with data from subscribeToKey deferred logic.
822-
if (pendingSubscriptionKeys.has(key) || (collectionKey && pendingSubscriptionKeys.has(collectionKey))) {
823-
const macrotaskPromise = new Promise<void>((resolve) => {
824-
setTimeout(() => resolve(), 0);
812+
function prepareSubscriberUpdate(callback: () => void): Promise<void> {
813+
if (!nextMacrotaskPromise) {
814+
nextMacrotaskPromise = new Promise<void>((resolve) => {
815+
setTimeout(() => {
816+
nextMacrotaskPromise = null;
817+
resolve();
818+
}, 0);
825819
});
826-
return Promise.all([macrotaskPromise, Promise.resolve().then(callback)]).then();
827820
}
828-
829-
return Promise.resolve().then(callback);
821+
return Promise.all([nextMacrotaskPromise, Promise.resolve().then(callback)]).then();
830822
}
831823

832824
/**
@@ -841,7 +833,7 @@ function scheduleSubscriberUpdate<TKey extends OnyxKey>(
841833
canUpdateSubscriber: (subscriber?: CallbackToStateMapping<OnyxKey>) => boolean = () => true,
842834
isProcessingCollectionUpdate = false,
843835
): Promise<void> {
844-
return prepareSubscriberUpdate(key, () => keyChanged(key, value, canUpdateSubscriber, isProcessingCollectionUpdate));
836+
return prepareSubscriberUpdate(() => keyChanged(key, value, canUpdateSubscriber, isProcessingCollectionUpdate));
845837
}
846838

847839
/**
@@ -854,7 +846,7 @@ function scheduleNotifyCollectionSubscribers<TKey extends OnyxKey>(
854846
value: OnyxCollection<KeyValueMapping[TKey]>,
855847
previousValue?: OnyxCollection<KeyValueMapping[TKey]>,
856848
): Promise<void> {
857-
return prepareSubscriberUpdate(key, () => keysChanged(key, value, previousValue));
849+
return prepareSubscriberUpdate(() => keysChanged(key, value, previousValue));
858850
}
859851

860852
/**
@@ -1103,10 +1095,7 @@ function subscribeToKey<TKey extends OnyxKey>(connectOptions: ConnectOptions<TKe
11031095
// We create a mapping from key to lists of subscriptionIDs to access the specific list of subscriptionIDs.
11041096
storeKeyBySubscriptions(mapping.key, callbackToStateMapping[subscriptionID].subscriptionID);
11051097

1106-
pendingSubscriptionKeys.add(mapping.key);
1107-
11081098
if (mapping.initWithStoredValues === false) {
1109-
pendingSubscriptionKeys.delete(mapping.key);
11101099
return subscriptionID;
11111100
}
11121101

@@ -1152,7 +1141,8 @@ function subscribeToKey<TKey extends OnyxKey>(connectOptions: ConnectOptions<TKe
11521141

11531142
// Here we cannot use batching because the nullish value is expected to be set immediately for default props
11541143
// or they will be undefined.
1155-
return sendDataToConnection(mapping, null, undefined);
1144+
sendDataToConnection(mapping, null, undefined);
1145+
return;
11561146
}
11571147

11581148
// When using a callback subscriber we will either trigger the provided callback for each key we find or combine all values
@@ -1161,25 +1151,25 @@ function subscribeToKey<TKey extends OnyxKey>(connectOptions: ConnectOptions<TKe
11611151
if (typeof mapping.callback === 'function') {
11621152
if (isCollectionKey(mapping.key)) {
11631153
if (mapping.waitForCollectionCallback) {
1164-
return getCollectionDataAndSendAsObject(matchingKeys, mapping);
1154+
getCollectionDataAndSendAsObject(matchingKeys, mapping);
1155+
return;
11651156
}
11661157

11671158
// We did not opt into using waitForCollectionCallback mode so the callback is called for every matching key.
1168-
return multiGet(matchingKeys).then((values) => {
1159+
multiGet(matchingKeys).then((values) => {
11691160
values.forEach((val, key) => {
11701161
sendDataToConnection(mapping, val as OnyxValue<TKey>, key as TKey);
11711162
});
11721163
});
1164+
return;
11731165
}
11741166

11751167
// If we are not subscribed to a collection key then there's only a single key to send an update for.
1176-
return get(mapping.key).then((val) => sendDataToConnection(mapping, val as OnyxValue<TKey>, mapping.key));
1168+
get(mapping.key).then((val) => sendDataToConnection(mapping, val as OnyxValue<TKey>, mapping.key));
1169+
return;
11771170
}
11781171

11791172
console.error('Warning: Onyx.connect() was found without a callback');
1180-
})
1181-
.then(() => {
1182-
pendingSubscriptionKeys.delete(mapping.key);
11831173
});
11841174

11851175
// The subscriptionID is returned back to the caller so that it can be used to clean up the connection when it's no longer needed

0 commit comments

Comments
 (0)