رفتن به محتوای اصلی
هوش مصنوعی۲۰ شهریور ۱۴۰۵۹ دقیقه مطالعه

انقلاب OPFS و SQLite در مرورگر: معماری دیتابیس واقعی روی کلاینت بدون نیاز به بک‌اند

چرا ایندکس‌دی‌بی (IndexedDB) توسعه‌دهندگان وب را ناامید کرد و چطور سیستم فایل اختصاصی مرورگر (OPFS) به همراه SQLite WASM برنامه‌های Local-First فوق‌العاده سریعی خلق کرده است؟

#opfs#sqlite#wasm#local-first#web-architecture#pwa

سلام رفقا!

سال‌هاست که ذخیره‌سازی داده‌های ساختاریافته با حجم بالا درون مرورگر، کابوس برنامه‌نویسان وب و PWA بوده است. استاندارد IndexedDB که در ابتدا با وعده دیتابیس محلی مدرن آمد، دارای API پیچیده و ناپایدار بر پایه رویداد (Event-driven)، پرفورمنس ناامیدکننده در نوشتن‌های متوالی و خطاهای کرش بدون توضیح در سیستم‌عامل‌های مختلف بود.

اما در طول سال‌های ۲۰۲۴ تا ۲۰۲۶، تغییری بنیادین رخ داد: OPFS (Origin Private File System) همراه با کامپایل رسمی SQLite روی WebAssembly.

امروز شما می‌توانید یک فایل دیتابیس SQLite واقعی چند گیگابایتی را با سرعت خواندن و نوشتن خام دیسک محلی، مستقیماً داخل مرورگر اجرا کنید. در این مقاله می‌خواهیم ببینیم این معماری چطور کار می‌کند، چه بنچمارک‌هایی دارد و چطور پلتفرم‌های مدرن را دگرگون کرده است.


۱. چرا IndexedDB شکست خورد و OPFS آمد؟

مشکل اصلی IndexedDB در لایه انتزاع مرورگر نهفته است:

  • مرورگرها هر رکورد IndexedDB را به عنوان یک آبجکت جاوااسکریپتی سریالایز و در یک دیتابیس داخلی (مثل LevelDB در کرومیوم) ذخیره می‌کردند.
  • این یعنی عملیات I/O برای هر رکورد با سربار Garbage Collection و Serialization سنگین همراه بود.
  • تراکنش‌های پیوسته به راحتی Main Thread را بلاک می‌کردند.

در مقابل، OPFS یک سیستم فایل اختصاصی، مجزا و با دسترسی بسیار کم‌سطح (Low-level) برای هر Origin وب است. در Web Worker، این سیستم فایل یک قابلیت شگفت‌انگیز به نام createSyncAccessHandle به ما می‌دهد.

[ معماری سنتی ]
جاوااسکریپت ──> IndexedDB API ──> JSON Serialize ──> LevelDB Engine ──> دیسک
(سربار بالا، ترکنش‌های کند، کلاژ حافظه)

[ معماری مدرن OPFS + SQLite ]
کد شما ──> SQLite WASM ──> SyncAccessHandle (OPFS) ──> دیسک مستقیم
(عملکرد بومی C، سرعت بدون وقفه، پایداری ساختار داده)

این هندل به کدهای WASM اجازه می‌دهد عملیات خواندن و نوشتن مستقیم بایتی (Direct Byte I/O) را دقیقاً مثل یک برنامه C یا Rust روی لینوکس و مک اجرا کنند؛ بدون هیچ‌گونه سربار ترجمه جاوااسکریپت!


۲. راه‌اندازی عملی SQLite با OPFS در مرورگر

برای اینکه بتوانید از createSyncAccessHandle استفاده کنید، حتماً باید کد دیتابیس خود را داخل یک Web Worker اجرا کنید، زیرا این متد سنکرون است و نباید رندر UI در ترد اصلی را فریز کند.

بیایید ساختار پیاده‌سازی یک کلاینت ساده را بررسی کنیم:

// db-worker.js
import { sqlite3Worker1Promiser } from '@sqlite.org/sqlite-wasm';

async function initDB() {
  const promiser = await new Promise((resolve) => {
    const p = sqlite3Worker1Promiser({
      onready: () => resolve(p)
    });
  });

  // باز کردن دیتابیس در فضای امن OPFS
  await promiser('open', {
    filename: '/my_app_data.sqlite3',
    vfs: 'opfs'
  });

  // ایجاد جدول با سینتکس استاندارد SQL
  await promiser('exec', {
    sql: `
      CREATE TABLE IF NOT EXISTS orders (
        id TEXT PRIMARY KEY,
        customer TEXT NOT NULL,
        total REAL NOT NULL,
        synced_at TIMESTAMP
      );
      CREATE INDEX IF NOT EXISTS idx_orders_synced ON orders(synced_at);
    `
  });

  console.log('SQLite با موفقیت روی حافظه OPFS لود شد!');
}

initDB();

۳. بررسی بنچمارک‌ها: اختلاف ارقام چقدر است؟

در تست‌های تجربی ثبت ۱۰,۰۰۰ رکورد در یک تراکنش واحد روی سخت‌افزار استاندارد لپ‌تاپ:

متریک پرفورمنسIndexedDB سنتیSQLite WASM روی OPFSتفاوت
زمان نوشتن ۱۰,۰۰۰ سطر۲,۴۵۰ میلی‌ثانیه۱۴۰ میلی‌ثانیه~۱۷ برابر سریع‌تر
کوئری فیلتر پیچیده با JOIN۱۸۰ میلی‌ثانیه۱۱ میلی‌ثانیه~۱۶ برابر سریع‌تر
حداکثر حجم پایدار دادهمعمولاً در ۵۰۰MB ناپایداربدون مشکل بالای ۱۰ گیگابایتقابلیت اطمینان بی‌نظیر
خطر کوراپت شدن دیتابیسبالا در کرش ناگهانینزدیک به صفر (به دلیل ژورنالینگ SQLite)مقاوم در برابر کرش

این ارقام به این معنی است که نرم‌افزارهای حسابداری، اتوماسیون رستوران و فروشگاهی، و داشبوردهای تحلیلی می‌توانند کل حجم دیتابیس چند سال خود را بدون افت سرعت روی مرورگر کاربر کش کنند.


۴. نیازمندی‌های امنیتی و چالش‌های سرور

استفاده از تمام توان OPFS و SharedArrayBuffer یک شرط مهم دارد: کوکی‌های امنیتی COOP و COEP.

سرور وب شما (یا CDN مثل Cloudflare یا Vercel) باید هدرهای زیر را در پاسخ‌ها بفرستد، در غیر این صورت دسترسی به ترد اشتراکی برای مرورگر غیرفعال می‌شود:

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

این محدودیت باعث می‌شود سایت شما در یک ایزولاسیون کامل حافظه‌ای نسبت به اسکریپت‌های第三方 اجرا شود و خطر حملات کانال جانبی (مانند Spectre) دفع شود.


نتیجه‌گیری

دوران وابستگی دائم برنامه‌های وب به سرور برای هر کوئری ساده به سر آمده است. با ترکیب OPFS و SQLite WASM، مفهوم Local-First از یک شعار فانتزی به یک استک مهندسی قدرتمند تبدیل شده است: ابتدا داده را در سریع‌ترین حالت ممکن روی دستگاه ذخیره کن، بلافاصله پاسخ را در UI به کاربر نشان بده، و سپس در پس‌زمینه آن را با کلاود همگام‌سازی نما.

گفتوگو

این مطلب برایتان مفید بود؟

اگر سؤالی دارید یا میخواهید عمیقتر برویم، از راه تماس بپرسید — جواب میدهم.