Performance Optimization
This page’s content is being updated
This guide covers performance optimization strategies for the Privacy Boost TypeScript SDK.
WASM Loading
Lazy Loading
The WASM module is large. Load it only when needed:
// Don't import at top level in routes that don't need it
// Instead, dynamically import when needed
async function initPrivacy() {
const { PrivacyBoost } = await import('@testinprod-io/privacy-boost');
return await PrivacyBoost.create(config);
}
Preloading
For routes that will need the SDK, preload in the background:
// In your app initialization
function preloadSDK() {
// Preload WASM in background
import('@testinprod-io/privacy-boost').then(({ loadWasm }) => {
loadWasm().catch(() => {
// Ignore preload errors
});
});
}
// Call early in your app
useEffect(() => {
preloadSDK();
}, []);
Code Splitting
Use route-based code splitting:
// React Router example
const PrivacyWallet = React.lazy(() => import('./PrivacyWallet'));
function App() {
return (
<Routes>
<Route path="/wallet" element={
<Suspense fallback={<Loading />}>
<PrivacyWallet />
</Suspense>
} />
</Routes>
);
}
Balance Caching
Local Cache
The SDK caches balances automatically. Control cache behavior:
// Get cached balance (fast)
const cachedBalance = useBalanceStore.getState().balances.get(tokenAddress);
// Force refresh from indexer (slow)
await sdk.vault.syncBalance(tokenAddress);
const freshBalance = await sdk.vault.getBalance(tokenAddress);
Smart Refresh
Only refresh when needed:
const CACHE_DURATION = 30000; // 30 seconds
function useBalance(tokenAddress: string) {
const [balance, setBalance] = useState<bigint>(0n);
const lastFetch = useRef<number>(0);
const refresh = useCallback(async () => {
const now = Date.now();
if (now - lastFetch.current < CACHE_DURATION) {
return; // Use cached
}
await sdk.vault.syncBalance(tokenAddress);
setBalance(await sdk.vault.getBalance(tokenAddress));
lastFetch.current = now;
}, [tokenAddress]);
return { balance, refresh };
}
Batch Operations
Sync all balances at once instead of individually:
// SLOW - Multiple requests
for (const token of tokens) {
await sdk.vault.syncBalance(token);
}
// FAST - Single batch request
await sdk.vault.syncAllBalances();
Render Optimization
Selective State Subscription
// BAD - Re-renders on any store change
function BadComponent() {
const store = useWalletStore(); // Subscribes to everything
return <div>{store.address}</div>;
}
// GOOD - Re-renders only when address changes
function GoodComponent() {
const address = useWalletStore((state) => state.address);
return <div>{address}</div>;
}
Shallow Comparison
import { shallow } from 'zustand/shallow';
// Only re-renders when these specific values change
const { address, chainId } = useWalletStore(
(state) => ({ address: state.address, chainId: state.chainId }),
shallow
);
Memoization
function BalanceList() {
const { balances } = useBalanceStore();
// Memoize expensive calculations
const sortedBalances = useMemo(() =>
Array.from(balances.values())
.filter((b) => b.shielded > 0n)
.sort((a, b) => Number(b.shielded - a.shielded)),
[balances]
);
return (
<ul>
{sortedBalances.map((b) => (
<BalanceItem key={b.tokenAddress} balance={b} />
))}
</ul>
);
}
// Memoize child components
const BalanceItem = React.memo(({ balance }: { balance: TokenBalance }) => (
<li>{balance.symbol}: {balance.shielded.toString()}</li>
));
Network Optimization
Request Debouncing
import { debounce } from 'lodash';
const debouncedSearch = useMemo(
() => debounce(async (query: string) => {
const results = await sdk.contacts.search(query);
setContacts(results);
}, 300),
[]
);
function ContactSearch() {
return (
<input
type="text"
onChange={(e) => debouncedSearch(e.target.value)}
placeholder="Search contacts..."
/>
);
}
Request Deduplication
const pendingRequests = new Map<string, Promise<unknown>>();
async function deduplicatedRequest<T>(
key: string,
request: () => Promise<T>
): Promise<T> {
if (pendingRequests.has(key)) {
return pendingRequests.get(key) as Promise<T>;
}
const promise = request().finally(() => {
pendingRequests.delete(key);
});
pendingRequests.set(key, promise);
return promise;
}
// Usage
const balance = await deduplicatedRequest(
`balance:${tokenAddress}`,
() => sdk.vault.getBalance(tokenAddress)
);
Parallel Requests
// SLOW - Sequential
const balance1 = await sdk.vault.getBalance(token1);
const balance2 = await sdk.vault.getBalance(token2);
const balance3 = await sdk.vault.getBalance(token3);
// FAST - Parallel
const [balance1, balance2, balance3] = await Promise.all([
sdk.vault.getBalance(token1),
sdk.vault.getBalance(token2),
sdk.vault.getBalance(token3),
]);
Memory Management
Cleanup Subscriptions
useEffect(() => {
const unsubscribe = useBalanceStore.subscribe((state) => {
// Handle changes
});
return () => unsubscribe(); // Important!
}, []);
Clear Unused Data
// Clear balances when logging out
async function logout() {
await sdk.auth.logout();
useBalanceStore.getState().clearBalances();
useTransactionStore.getState().clearTransactions();
}
Limit History Size
// Fetch only what you need
const recentTxs = await sdk.transactions.fetchHistory({
limit: 20, // Don't fetch everything
});
Bundle Size
Tree Shaking
Import only what you need:
// BAD - Imports entire package
import * as SDK from '@testinprod-io/privacy-boost';
// GOOD - Tree-shakeable imports
import { PrivacyBoost, Eip1193WalletAdapter } from '@testinprod-io/privacy-boost';
Analyze Bundle
# Webpack
npx webpack-bundle-analyzer stats.json
# Vite
npx vite-bundle-visualizer
Track Operation Duration
async function timedOperation<T>(
name: string,
operation: () => Promise<T>
): Promise<T> {
const start = performance.now();
try {
return await operation();
} finally {
const duration = performance.now() - start;
console.log(`${name}: ${duration.toFixed(2)}ms`);
// Send to analytics
if (duration > 5000) {
trackSlowOperation(name, duration);
}
}
}
// Usage
const result = await timedOperation('deposit', () =>
sdk.vault.deposit(params)
);
Use React DevTools Profiler to identify slow renders.
Best Practices Summary
- Lazy load WASM - Don’t block initial page load
- Use cache wisely - Balance freshness vs performance
- Select specific state - Avoid unnecessary re-renders
- Batch operations - Reduce network requests
- Memoize calculations - Avoid redundant work
- Clean up subscriptions - Prevent memory leaks
- Monitor performance - Track slow operations
Next Steps