مساحة تخزين عالية الأداء لتطبيقك: واجهة برمجة التطبيقات Storage Foundation

يوفر النظام الأساسي للويب للمطورين بشكل متزايد الأدوات التي يحتاجونها لإنشاء تطبيقات عالية الأداء ومحسنة للويب. وعلى وجه التحديد، أتاحت WebAssembly (Wasm) المجال لاستخدام تطبيقات ويب سريعة وفعّالة، في حين أنّ تقنيات مثل Emscripten تتيح الآن للمطوّرين إعادة استخدام الرموز البرمجية التي تمت تجربتها واختبارها على الويب. لتحقيق أقصى استفادة من هذه الإمكانات، يجب أن يتمتع مطورو البرامج بنفس القوة والمرونة في ما يتعلق بالتخزين.

وهنا يأتي دور واجهة برمجة تطبيقات Storage Foundation. Storage Foundation API هي واجهة برمجة تطبيقات جديدة وسريعة وغير مفعَّلة للتخزين تتيح للمستخدمين اكتشاف حالات استخدام جديدة ومطلوبة على الويب، مثل تنفيذ قواعد بيانات فعّالة وإدارة الملفات المؤقتة الكبيرة بسلاسة. باستخدام هذه الواجهة الجديدة، يمكن للمطوّرين "توفير مساحة تخزين خاصة بهم" على الويب، ما يقلل من الفجوة في الميزات بين الرموز البرمجية الخاصة بالويب والنظام الأساسي.

تم تصميم واجهة برمجة التطبيقات Storage Foundation لتشبه نظام ملفات أساسي، لذا فهي تمنح المطورين المرونة من خلال توفير قواعد أساسية عامة وبسيطة وذات أداء جيد يمكنهم من خلالها إنشاء مكونات ذات مستوى أعلى. ويمكن للتطبيقات الاستفادة من أفضل أداة لتلبية احتياجاتها، لإيجاد التوازن الصحيح بين سهولة الاستخدام والأداء والموثوقية.

لماذا يحتاج الويب إلى واجهة برمجة تطبيقات أخرى للتخزين؟

تقدم منصة الويب عددًا من خيارات التخزين للمطورين، وقد تم تصميم كل منها مع وضع حالات استخدام محددة في الاعتبار.

  • من الواضح أنّ بعض هذه الخيارات لا تتداخل مع هذا الاقتراح لأنّها لا تسمح بتخزين سوى كميات صغيرة جدًا من البيانات، مثل ملفات تعريف الارتباط، أو Web Storage API التي تتألف من آلية sessionStorage وlocalStorage.
  • سبق أن تم إيقاف الخيارات الأخرى لأسباب مختلفة مثل واجهة برمجة تطبيقات الملفات والدليل المُدخلات أو WebSQL.
  • تحتوي File System Access API على واجهة برمجة تطبيقات مشابهة، ولكن يتم استخدامها للتفاعل مع نظام الملفات لدى العميل وتوفير إمكانية الوصول إلى البيانات التي قد تكون خارج ملكية المصدر أو حتى ملكية المتصفّح. يأتي هذا التركيز المختلف مع اعتبارات أمان أكثر صرامة وتكاليف أداء أعلى.
  • يمكن استخدام IndexedDB API كخلفية لبعض حالات استخدام Storage Foundation API. على سبيل المثال، يتضمن Emscripten IDBFS، وهو نظام ملفات دائم مستند إلى IndexedDB. ومع ذلك، ونظرًا لأن IndexedDB هو مخزن القيم الأساسية بشكل أساسي، فإنّه تأتي مع قيود كبيرة على الأداء. بالإضافة إلى ذلك، يكون الوصول المباشر إلى الأقسام الفرعية من أحد الملفات أكثر صعوبة وأبطأ ضمن IndexedDB.
  • أخيرًا، يتم دعم واجهة ذاكرة التخزين المؤقت على نطاق واسع، ويتم ضبطها لتخزين البيانات الكبيرة الحجم مثل موارد تطبيق الويب، إلا أنّ القيم غير قابلة للتغيير.

إنّ Storage Foundation API عبارة عن محاولة لسد كل الثغرات في خيارات مساحة التخزين السابقة من خلال السماح بالتخزين الفعّال للملفات الكبيرة القابلة للتغيير التي تم تحديدها في أصل التطبيق.

حالات الاستخدام المقترَحة لواجهة برمجة تطبيقات Storage Foundation

في ما يلي أمثلة على المواقع الإلكترونية التي قد تستخدم واجهة برمجة التطبيقات هذه:

  • تطبيقات الإنتاجية أو الإبداع التي تعمل على كميات كبيرة من بيانات الفيديو أو الصوت أو الصور. يمكن لهذه التطبيقات تفريغ أجزاء من القرص إلى القرص بدلاً من الاحتفاظ بها في الذاكرة.
  • التطبيقات التي تعتمد على نظام ملفات دائم يمكن الوصول إليها من Wasm والتي تحتاج إلى أداء أعلى مما يمكن أن يضمنه IDBFS.

ما هي واجهة برمجة التطبيقات Storage Foundation؟

هناك جزءان رئيسيان في واجهة برمجة التطبيقات:

  • استدعاءات نظام الملفات، التي توفر وظائف أساسية للتفاعل مع الملفات ومسارات الملفات.
  • أسماء الملفات، التي توفر إمكانية الوصول للقراءة والكتابة إلى ملف حالي

مكالمات نظام الملفات

تقدّم واجهة برمجة التطبيقات Storage Foundation عنصرًا جديدًا، وهو storageFoundation، ويتوفّر على كائن window، ويتضمّن عددًا من الدوال:

  • storageFoundation.open(name): يتم فتح الملف بالاسم المحدّد إذا كان متوفّرًا ويتم إنشاء ملف جديد بأي طريقة أخرى. تعرض هذه القيمة وعدًا يتم حلّه مع الملف المفتوح.
  • storageFoundation.delete(name): لإزالة الملف الذي يحمل الاسم الأول. تعرض وعدًا يتم حله عند حذف الملف.
  • storageFoundation.rename(oldName, newName): يعيد تسمية الملف من الاسم القديم إلى الاسم الجديد بشكل مكثف. تعرض وعدًا يتم حله عند إعادة تسمية الملف.
  • storageFoundation.getAll(): يتم عرض وعد يتم حلّه باستخدام مصفوفة من جميع أسماء الملفات الحالية.
  • storageFoundation.requestCapacity(requestedCapacity): طلب سعة جديدة (بالبايت) للاستخدام حسب سياق التنفيذ الحالي. تعرض وعدًا تم حله بالمقدار المتبقي من السعة المتاحة.
  • storageFoundation.releaseCapacity(toBeReleasedCapacity): يؤدي إلى إصدار العدد المحدّد من وحدات البايت من سياق التنفيذ الحالي، وعرض تعهد يتم حلّه بالسعة المتبقية.
  • storageFoundation.getRemainingCapacity(): تعرض وعدًا يتم حلّه باستخدام السعة المتاحة لسياق التنفيذ الحالي.

مؤشرات الملفات

يتم التعامل مع الملفات من خلال الدوال التالية:

  • NativeIOFile.close(): لإغلاق ملف، وعرض وعد يتم حلّه عند اكتمال العملية
  • NativeIOFile.flush(): يؤدي هذا الإجراء إلى مزامنة (أي مسح) حالة ذاكرة الملف مع جهاز التخزين، وعرض وعد يتم حلّه عند اكتمال العملية.
  • NativeIOFile.getLength(): يتم عرض وعد يتم مطابقته مع طول الملف بالبايت.
  • NativeIOFile.setLength(length): لضبط طول الملف بالبايت، وعرض وعد يتم حلّه عند اكتمال العملية. إذا كان الطول الجديد أصغر من الطول الحالي، تتم إزالة وحدات البايت بدءًا من نهاية الملف. وإلا فإن الملف يتم تمديده بوحدات بايت صفرية.
  • NativeIOFile.read(buffer, offset): يقرأ محتوى الملف بالإزاحة المحددة من خلال مورد احتياطي ناتج عن نقل المخزن المؤقت المحدد، ثم يتم تركه منفصلاً. تعرض NativeIOReadResult مع المخزن المؤقت المنقول وعدد وحدات البايت التي تمت قراءتها بنجاح.

    NativeIOReadResult هو كائن يتألف من إدخالَين:

    • buffer: ArrayBufferView، وهو نتيجة نقل المخزن المؤقت الذي تم تمريره إلى read(). إنه من نفس النوع والطول مثل المخزن المؤقت المصدر.
    • readBytes: عدد وحدات البايت التي تمت قراءتها بنجاح في buffer. قد يكون هذا أقل من حجم المخزن المؤقت، في حالة حدوث خطأ أو إذا كان نطاق القراءة يمتد إلى ما بعد نهاية الملف. يتم تعيينها على صفر إذا كان نطاق القراءة بعد نهاية الملف.
  • NativeIOFile.write(buffer, offset): يكتب محتوى المخزن المؤقت المحدد في الملف بالإزاحة المحددة. يتم نقل المخزن المؤقت قبل كتابة أي بيانات وبالتالي يتم تركه منفصلاً. لعرض NativeIOWriteResult مع المخزن المؤقت المنقول وعدد وحدات البايت التي تمت كتابتها بنجاح. سيتم تمديد الملف إذا تجاوز نطاق الكتابة طوله.

    NativeIOWriteResult هو كائن يتألف من إدخالَين:

    • buffer: ArrayBufferView وهو نتيجة نقل المخزن المؤقت الذي تم تمريره إلى write(). إنه من نفس النوع والطول مثل المخزن المؤقت المصدر.
    • writtenBytes: عدد وحدات البايت التي تمت كتابتها بنجاح في buffer. قد يكون هذا أقل من حجم المخزن المؤقت في حالة حدوث خطأ.

أمثلة كاملة

لتوضيح المفاهيم التي تم تقديمها أعلاه، إليك مثالين كاملين يطلعانك على المراحل المختلفة من دورة حياة ملفات Storage Foundation.

الفتح والكتابة والقراءة والإغلاق

// Open a file (creating it if needed).
const file = await storageFoundation.open('test_file');
try {
  // Request 100 bytes of capacity for this context.
  await storageFoundation.requestCapacity(100);

  const writeBuffer = new Uint8Array([64, 65, 66]);
  // Write the buffer at offset 0. After this operation, `result.buffer`
  // contains the transferred buffer and `result.writtenBytes` is 3,
  // the number of bytes written. `writeBuffer` is left detached.
  let result = await file.write(writeBuffer, 0);

  const readBuffer = new Uint8Array(3);
  // Read at offset 1. `result.buffer` contains the transferred buffer,
  // `result.readBytes` is 2, the number of bytes read. `readBuffer` is left
  // detached.
  result = await file.read(readBuffer, 1);
  // `Uint8Array(3) [65, 66, 0]`
  console.log(result.buffer);
} finally {
  file.close();
}

الفتح وبطاقة البيانات والحذف

// Open three different files (creating them if needed).
await storageFoundation.open('sunrise');
await storageFoundation.open('noon');
await storageFoundation.open('sunset');
// List all existing files.
// `["sunset", "sunrise", "noon"]`
await storageFoundation.getAll();
// Delete one of the three files.
await storageFoundation.delete('noon');
// List all remaining existing files.
// `["sunrise", "noon"]`
await storageFoundation.getAll();

تجريبي

يمكنك استخدام العرض التوضيحي لواجهة برمجة التطبيقات Storage Foundation API في التضمين أدناه. يمكنك إنشاء الملفات وإعادة تسميتها والكتابة عليها وقراءتها، ومعرفة السعة المتاحة التي طلبت التحديث أثناء إجراء التغييرات. يمكنك العثور على رمز المصدر الخاص بالعرض التوضيحي على Glitch.

الأمان والأذونات

لقد صمّم فريق Chromium واجهة برمجة التطبيقات Storage Foundation API ونفّذها باستخدام المبادئ الأساسية المحدّدة في التحكّم في الوصول إلى الميزات الفعّالة لمنصة الويب، بما في ذلك التحكّم في المستخدم والشفافية وتسهيل الاستخدام.

وباتّباع النمط نفسه المتّبع في واجهات برمجة التطبيقات لمساحة التخزين الحديثة الأخرى على الويب، يكون الوصول إلى واجهة برمجة تطبيقات "مؤسسة Storage" مرتبطًا بالمصدر، ما يعني أنّ المصدر لا يمكنه الوصول إلا إلى البيانات التي تم إنشاؤها ذاتيًا. وتقتصر أيضًا على السياقات الآمنة.

تحكم المستخدم

سيتم استخدام حصة مساحة التخزين لتوزيع إمكانية الوصول إلى مساحة القرص ولمنع إساءة الاستخدام. يجب طلب الذاكرة التي تريد شغلها أولاً. مثلما هو الحال مع واجهات برمجة التطبيقات الأخرى للتخزين، يمكن للمستخدمين إخلاء المساحة التي استغلتها واجهة برمجة تطبيقات Storage Foundation من خلال المتصفّح.

روابط مفيدة

شكر وتقدير

تم تحديد Storage Foundation API وتنفيذه من قِبل إيمانويل كريفوي وريتشارد ستوتس. تمّت مراجعة هذه المقالة من قِبل بيت ليب وجو ميدلي.

صورة رئيسية تم تقديمها بواسطة Markus Spiske على Unsplash