توفّر منصة الويب بشكل متزايد الأدوات التي يحتاج إليها المطوّرون لإنشاء تطبيقات عالية الأداء ومحسّنة للويب. من أهم التطورات، أنّ 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 API كخادم خلفي لبعض حالات استخدام 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();
الأمان والأذونات
صمّم فريق Chromium واجهة Storage Foundation API ونفّذها باستخدام المبادئ الأساسية المحدّدة في التحكّم في الوصول إلى الميزات الفعّالة لمنصة الويب، بما في ذلك تحكّم المستخدم وشفافية الاستخدام وسهولة الاستخدام.
باتّباع النمط نفسه الذي تتّبعه واجهات برمجة التطبيقات الحديثة الأخرى للتخزين على الويب، يكون الوصول إلى Storage Foundation API مرتبطًا بالمصدر، ما يعني أنّه لا يمكن للمصدر الوصول إلا إلى البيانات التي أنشأها بنفسه. ويقتصر أيضًا على السياقات الآمنة.
تحكّم المستخدم
سيتم استخدام حصة التخزين لتوزيع إذن الوصول إلى مساحة القرص ومنع إساءة الاستخدام. يجب أولاً طلب الذاكرة التي تريد شغلها. وكما هو الحال مع واجهات برمجة التطبيقات الأخرى المتعلّقة بمساحة التخزين، يمكن للمستخدمين محو المساحة التي تشغلها Storage Foundation API من خلال المتصفّح.
روابط مفيدة
- شرح علني
- خطأ تتبُّع Chromium
- إدخال ChromeStatus.com
- مكوّن Blink:
Blink>Storage>NativeIO
- مراجعة TAG
- Intent to Prototype
- سلسلة WebKit
- سلسلة محادثات Mozilla
الإقرارات
تم تحديد مواصفات واجهة برمجة التطبيقات Storage Foundation وتنفيذها من قِبل إيمانويل كريفوي وريتشارد ستوتز. راجع هذه المقالة بيت ليباج وجو ميدلي.
الصورة الرئيسية من ماركوس سبيسكي على Unsplash