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

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

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

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

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

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

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

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

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

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

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

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

تتضمّن واجهة برمجة التطبيقات جزءَين رئيسيَّين:

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

طلبات نظام الملفات

تقدّم Storage Foundation API عنصرًا جديدًا، وهو 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 Foundation مرتبطًا بالمصدر، ما يعني أنّ المصدر يمكنه الوصول إلى البيانات التي أنشأها بنفسه فقط. ويقتصر أيضًا على السياقات الآمنة.

التحكّم في المستخدم

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

روابط مفيدة

الشكر والتقدير

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

الصورة الرئيسية من خلال Markus Spiske على Unsplash.