Running sync operations synchronously on the JavaScript thread blocks the event loop, freezing animations, touch responses, and navigation during large data transfers. ISO 25010:2011 performance-efficiency.time-behaviour requires that background operations do not degrade foreground frame rate. A frozen UI during sync is indistinguishable from a crash for the user — they force-quit the app, potentially interrupting the sync and corrupting queue state. Sync must be non-blocking even when processing hundreds of queued records.
Medium because UI freezes degrade perceived reliability and can interrupt sync mid-flight, but the defect does not expose data or enable exploitation.
Move heavy sync work to a background task using react-native-background-fetch or Expo's TaskManager. For foreground sync, ensure every I/O operation uses async/await and never calls synchronous storage APIs.
// npm install react-native-background-fetch
import BackgroundFetch from 'react-native-background-fetch';
export function registerBackgroundSync() {
BackgroundFetch.configure(
{ minimumFetchInterval: 15, stopOnTerminate: false, startOnBoot: true },
async (taskId) => {
try {
await drainQueue(executeAction);
await fetchRemoteUpdates();
} finally {
BackgroundFetch.finish(taskId);
}
},
(err) => console.error('BackgroundFetch failed to start:', err)
);
}
For in-app sync, never use AsyncStorage.getItemSync or equivalent; every call must be awaited. Wrap sync triggers in a debounce so rapid reconnect/disconnect cycles don't spawn concurrent sync runs.
ID: mobile-offline-storage.offline-behavior.non-blocking-sync
Severity: medium
What to look for: Examine how data syncing is implemented. Look for use of background tasks, web workers, or non-blocking async patterns. Check that sync operations don't freeze the UI.
Pass criteria: Count all sync operation call sites. Sync operations run asynchronously (using async/await or Promise patterns) without blocking the main UI thread. App remains interactive during sync. At least 1 sync function uses non-blocking async patterns.
Fail criteria: Sync operations run synchronously on the main thread and freeze the UI during large data transfers.
Skip (N/A) when: Never — non-blocking sync is essential for user experience.
Detail on fail: "Data sync runs on main thread. App freezes for 3-5 seconds during sync, making UI unresponsive."
Remediation: Use background task scheduling:
// Install: npm install react-native-background-fetch
import BackgroundFetch from 'react-native-background-fetch';
BackgroundFetch.configure(
{
minimumFetchInterval: 15, // minutes
stopOnTerminate: false,
startOnBoot: true,
},
async (taskId) => {
console.log('Background sync task:', taskId);
try {
await processQueue();
await syncData();
BackgroundFetch.finish(taskId);
} catch (error) {
console.error('Background sync failed:', error);
BackgroundFetch.finish(taskId);
}
},
(error) => {
console.error('BackgroundFetch error:', error);
}
);