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

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

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

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

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

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

  • من الواضح أنّ بعض هذه الخيارات لا تتداخل مع هذا الاقتراح لأنّها لا تسمح إلا بكميات قليلة جدًا من البيانات التي يتم تخزينها، مثل ملفات تعريف الارتباط، أو واجهة برمجة التطبيقات Web Storage API التي تتألف من آليات sessionStorage وlocalStorage.
  • ويتم إيقاف الخيارات الأخرى نهائيًا لأسباب مختلفة مثل واجهة برمجة تطبيقات إدخالات الملفات والدليل أو 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.