Performance Optimization¶
Best practices for creating fast and efficient Movian plugins.
Overview¶
Performance optimization focuses on: - Fast page loading - Efficient data processing - Minimal memory usage - Smooth UI updates - Network efficiency
Async Operations¶
Use Async HTTP Requests¶
// GOOD: Async request
page.loading = true;
http.request(url, function(err, response) {
page.loading = false;
if (!err) {
processData(response);
}
});
// BAD: Blocks plugin thread
var response = http.request(url); // Synchronous
Parallel Requests¶
// Load multiple resources in parallel
var pending = 2;
var results = {};
function checkComplete() {
if (--pending === 0) {
displayResults(results);
}
}
http.request(url1, function(err, response) {
results.data1 = response;
checkComplete();
});
http.request(url2, function(err, response) {
results.data2 = response;
checkComplete();
});
Caching Strategies¶
Memory Cache¶
var cache = {};
var CACHE_TTL = 3600000; // 1 hour
function getCached(key) {
var entry = cache[key];
if (entry && Date.now() - entry.time < CACHE_TTL) {
return entry.data;
}
return null;
}
function setCache(key, data) {
cache[key] = {
data: data,
time: Date.now()
};
}
Persistent Cache¶
var store = require('movian/store');
function getCachedData(key) {
var cached = store[key];
if (cached) {
var data = JSON.parse(cached);
if (Date.now() - data.timestamp < 3600000) {
return data.value;
}
}
return null;
}
function setCachedData(key, value) {
store[key] = JSON.stringify({
value: value,
timestamp: Date.now()
});
}
Data Processing¶
Lazy Loading¶
// Load data incrementally
function loadPage(page, offset, limit) {
var url = baseUrl + "?offset=" + offset + "&limit=" + limit;
http.request(url, function(err, response) {
if (!err) {
var data = JSON.parse(response.toString());
displayItems(page, data.items);
// Load more if available
if (data.hasMore) {
loadPage(page, offset + limit, limit);
}
}
});
}
loadPage(page, 0, 20); // Start with 20 items
Batch Operations¶
// BAD: Individual database inserts
for (var i = 0; i < 1000; i++) {
db.exec("INSERT INTO items VALUES (" + i + ")");
}
// GOOD: Batch with transaction
db.begin();
var stmt = db.prepare("INSERT INTO items VALUES (?)");
for (var i = 0; i < 1000; i++) {
stmt.bind(i).execute();
}
stmt.finalize();
db.commit();
Memory Management¶
Avoid Memory Leaks¶
// BAD: Leaks subscriptions
function createPage() {
prop.subscribe(someProp, function() {
// Callback never cleaned up
});
}
// GOOD: Clean up subscriptions
function createPage() {
var subscriptions = [];
subscriptions.push(prop.subscribe(someProp, callback));
page.onDestroy(function() {
subscriptions.forEach(function(sub) {
sub.destroy();
});
});
}
Limit Cache Size¶
var cache = {};
var MAX_CACHE_SIZE = 100;
var cacheKeys = [];
function setCache(key, value) {
if (cacheKeys.length >= MAX_CACHE_SIZE) {
var oldKey = cacheKeys.shift();
delete cache[oldKey];
}
cache[key] = value;
cacheKeys.push(key);
}
Network Optimization¶
Request Throttling¶
var requestQueue = [];
var activeRequests = 0;
var MAX_CONCURRENT = 4;
function queueRequest(url, callback) {
requestQueue.push({url: url, callback: callback});
processQueue();
}
function processQueue() {
while (activeRequests < MAX_CONCURRENT && requestQueue.length > 0) {
var req = requestQueue.shift();
activeRequests++;
http.request(req.url, function(err, response) {
activeRequests--;
req.callback(err, response);
processQueue();
});
}
}
Request Deduplication¶
var pendingRequests = {};
function deduplicatedRequest(url, callback) {
if (pendingRequests[url]) {
pendingRequests[url].push(callback);
return;
}
pendingRequests[url] = [callback];
http.request(url, function(err, response) {
var callbacks = pendingRequests[url];
delete pendingRequests[url];
callbacks.forEach(function(cb) {
cb(err, response);
});
});
}
UI Performance¶
Minimize Property Updates¶
// BAD: Multiple updates trigger multiple redraws
page.metadata.title = "Title";
page.metadata.icon = "icon.png";
page.metadata.background = "bg.jpg";
// GOOD: Batch updates
var metadata = page.metadata;
metadata.title = "Title";
metadata.icon = "icon.png";
metadata.background = "bg.jpg";
Efficient Item Creation¶
// BAD: Create items one by one
items.forEach(function(item) {
page.appendItem("video", item.title, {url: item.url});
});
// GOOD: Prepare data first, then create items
var itemData = items.map(function(item) {
return {
type: "video",
title: item.title,
url: item.url
};
});
itemData.forEach(function(data) {
page.appendItem(data.type, data.title, {url: data.url});
});
Database Optimization¶
Use Indexes¶
// Create indexes for frequently queried columns
db.exec("CREATE INDEX IF NOT EXISTS idx_timestamp ON cache(timestamp)");
db.exec("CREATE INDEX IF NOT EXISTS idx_user_id ON history(user_id)");
Prepared Statements¶
// BAD: Repeated parsing
for (var i = 0; i < 1000; i++) {
db.query("SELECT * FROM users WHERE id = " + i);
}
// GOOD: Prepared statement
var stmt = db.prepare("SELECT * FROM users WHERE id = ?");
for (var i = 0; i < 1000; i++) {
var results = stmt.bind(i).execute();
}
stmt.finalize();
Profiling and Measurement¶
Timing Operations¶
function measureTime(name, func) {
var start = Date.now();
var result = func();
var elapsed = Date.now() - start;
console.log(name + " took " + elapsed + "ms");
return result;
}
// Usage
measureTime("Data processing", function() {
return processLargeDataset(data);
});
Memory Usage¶
// Monitor cache size
function getCacheSize() {
var size = 0;
for (var key in cache) {
size += JSON.stringify(cache[key]).length;
}
return size;
}
console.log("Cache size:", getCacheSize(), "bytes");
Best Practices¶
Do's ✅¶
- Use async operations for I/O
- Cache frequently accessed data
- Use prepared statements for databases
- Create indexes on queried columns
- Batch operations when possible
- Limit cache size
- Throttle network requests
- Clean up resources
- Profile performance bottlenecks
Don'ts ❌¶
- Don't block with synchronous operations
- Don't make excessive HTTP requests
- Don't store large objects in memory
- Don't update UI unnecessarily
- Don't ignore cache invalidation
- Don't leak subscriptions
- Don't use SELECT * in queries
- Don't ignore database transactions
See Also¶
- Best Practices - Development patterns
- HTTP API - Network operations
- SQLite API - Database operations
- Storage API - Data persistence