يمثل ArrayBuffer
جزءًا من معيار "ECMA"، وهو جزء من جافاسكريبت JavaScript، لكن توجد كائنات عالية المستوى ضمن المتصفح وُصِفت في الواجهة البرمجية الخاصة بالملفات File API وبالتحديد الكائن Blob
، والذي يتألف من نص افتراضي هو type
(من النوع متعدد الوسائط MIME عادةً)، بالإضافة إلى الوسيط blobParts
وهو سلسلة من كائنات Blob
أخرى ونصوص ومصدر للبيانات الثنائية BufferSource
.
تأخذ الدالة البانية الصيغة التالية:
new Blob(blobParts, options);
حيث:
-
blobParts
: هو مصفوفة قيمها كائناتBlob
وBufferSource
وString
. -
options
: ويتضمن كائنات اختياريةً هي: -
type
: يمثل نوع الكائنBlob
، وهو عادةً من النوع متعدد الوسائط MIME مثل: "image/png". -
endings
: ويحدد إن كنا سنحوّل محرف نهاية السطر للكائنBlob
بما يناسب نظام التشغيل الحالي (n\
أو\r\n\
)، وسيأخذ افتراضيًا القيمة "transparent" أي لا تفعل شيئًا، وقد يأخذ القيمة "native" أي أَجرِ التحويل.
إليك المثال التالي:
// (blob) إنشاء كائن بيانات ثنائية من نص let blob = new Blob(["<html>…</html>"], {type: 'text/html'}); // لاحظ أن الوسيط الأول هو مصفوفة // إنشاء كائن بيانات ثنائية من نص ومصفوفة let hello = new Uint8Array([72, 101, 108, 108, 111]); // "Hello" بالصيغة الثنائية let blob = new Blob([hello, ' ', 'world'], {type: 'text/plain'});
يمكن استخراج الشرائح المكونة للكائن Blob
كالتالي:
blob.slice([byteStart], [byteEnd], [contentType]);
حيث:
-
byteStart
: بايت البداية وافتراضيًا هو البايت 0. -
byteEnd
: البايت الأخير (ضمنًا، وافتراضيًا حتى آخر المخزن). -
contentType
: نوع كائنblob
الجديد، وسيكون افتراضيًا نفس نوع مصدر البيانات.
حيث تشابه هذه الوسائط مقابلاتها في التابع array.slice
، ويُسمح باستخدام القيم السالبة.
اقتباسالكائنات
Blob
هي كائنات ثابتةلا يمكن تغيير بيانات
Blob
مباشرةً، لكن يمكن اجتزاء شرائح منها أو إنشاء كائنBlob
جديد أو خلط البيانات في كائن جديد وهكذا، ويشابه هذا السلوك سلوك الكائنات النصية في JavaScript، حيث لا يمكن تغيير حرف في النص، لكن بالإمكان إنشاء نص جديد مصحح.
الكائن Blob كعنوان لمورد URL
يمكن استخدام الكائن Blob
مثل عناوين للرابط التشعبي <a>
ولمعرّف الصورة <img>
لإظهار محتوياتهما بفضل الوسيط type
، كما يمكن رفع أو تنزيل الكائنات Blob
، وسيتحول النوع type
بالطبع إلى Content-Type
في طلبات الشبكة network requests.
لنبدأ بالمثال البسيط التالي، فبالنقر على الرابط سينزل كائن Blob
مولَّد آليًا يحتوي على النص "Hello world" ضمن ملف:
<!-- download attribute forces the browser to download instead of navigating --> <a download="hello.txt" href='#' id="link">Download</a> <script> let blob = new Blob(["Hello, world!"], {type: 'text/plain'}); link.href = URL.createObjectURL(blob); </script>
بالإمكان أيضًا إنشاء رابط آليًا في JavaScript، ومن ثم محاكاة عملية النقر بزر الفأرة ()link.click
وسيبدأ بعدها التنزيل آليًا، إليك الشيفرة التالية التي تسمح للمستخدم بتنزيل كائن Blob
المولَّد آليًا دون أي شيفرة HTML:
let link = document.createElement('a'); link.download = 'hello.txt'; let blob = new Blob(['Hello, world!'], {type: 'text/plain'}); link.href = URL.createObjectURL(blob); link.click(); URL.revokeObjectURL(link.href);
يأخذ التابع URL.createObjectURL
الكائن Blob
مثل وسيط وينشئ عنوانًا له على الشكل <blob:<origin>/<uuid
.
ستبدو قيمة الخاصية link.href
كالتالي:
blob:https://javascript.info/1e67e00e-860d-40a5-89ae-6ab0cbee6273
يُخزِّن المتصفح كل عنوان يولّده التابع URL.createObjectURL
على شكل ارتباط map داخلي من الشكل "URL>Blob"، لذا ستكون هذه العناوين قصيرةً، لكنها تسمح بالوصول إلى الكائن Blob
، وسيكون العنوان المولَّد -وبالتالي الرابط المتعلق به- صالحًا ضمن المستند الحالي طالما كان مفتوحًا، كما سيسمح بتحديد مرجع للكائن في كل من <img>
و<a>
وغيرهما من الكائنات التي تحتاج إلى عنوان URL، ومع ذلك هنالك أثر جانبي، فعلى الرغم من ارتباط Blob
بالعنوان فهذا الكائن مقيم في الذاكرة، ولا يمكن للمتصفح تحرير الذاكرة المتعلقة به، وسيُزال الارتباط كليًا عند إنهاء المستند، وبالتالي ستتحرر الذاكرة المرتبطة بالكائنات Blob
، لكن إن استمر التطبيق لفترة طويلة فلن تحدث هذه العملية خلال فترة وجيزة.
إذا أنشأنا عنوانًا فسيبقى الكائن Blob
مقيمًا في الذاكرة حتى لو لم تَعُد هناك حاجة له.
يزيل التابع (URL.revokeObjectURL(url
المرجع من علاقة الارتباط الداخلي بين الكائن Blob
والعنوان متيحًا المجال لإزالته (إن لم يرتبط بمراجع أخرى) وتحرير الذاكرة، وقد حرصنا في المثال الأخير على استخدام Blob
مرةً واحدةً للتنزيل الفوري، لذلك سنستدعي مباشرةً الآتي:
URL.revokeObjectURL(link.href)
لم نستدع التابع (URL.revokeObjectURL(link.href
في مثالنا السابق الذي تضمن رابط HTML قابلًا للنقر، مما سيجعل الكائن Blob
غير صالح، ولن يعمل العنوان بعد إلغاء الارتباط المرجعي.
التحويل بين Blob ونص مشفر بطريقة base64
يمكن أن نحوّل الكائن Blob
إلى سلسلة نصية بتشفير base64 لتكون يمثابة وسيلة بديلة لاستخدام التابع URL.createObjectURL
، يمثل التشفير السابق البيانات الثنائية مثل نص يتكون من محارف ASCII من 0 حتى 64 قابلة للقراءة، ويتمتع بحيز أمان كبير جدًا، والأهم من ذلك إمكانية استخدام هذا التشفير مع عناوين موارد البيانات data urls، والتي لها الشكل:
<data:[<mediatype>][;base64],<data
يمكن استخدام هذه العناوين في أي مكان مثل العناوين النظامية. إليك طريقة تمثيل بيانات تعطي وجهًا تعبيريًا Smiley:
<img src="data:image/png;base64,R0lGODlhDAAMAKIFAF5LAP/zxAAAANyuAP/gaP///wAAAAAAACH5BAEAAAUALAAAAAAMAAwAAAMlWLPcGjDKFYi9lxKBOaGcF35DhWHamZUW0K4mAbiwWtuf0uxFAgA7">
حيث سيفكك المتصفح شيفرة البيانات ويعطي كنتيجة الوجه التعبيري التالي:
نستخدم الكائن FileReader
المدمج لتحويل Blob
إلى base64، حيث يستطيع قراءة البيانات من Blob
بصيغ مختلفة، وسنتعمق في هذا الموضوع أكثر في الفصل القادم.
إليك نموذجًا عن تنزيل Blob
من خلال التشفير base64 هذه المرة:
let link = document.createElement('a'); link.download = 'hello.txt'; let blob = new Blob(['Hello, world!'], {type: 'text/plain'}); let reader = new FileReader(); reader.readAsDataURL(blob); // استدعاء التحويل reader.onload = function() { link.href = reader.result; // عنوان بيانات link.click(); };
يمكن استخدام إحدى الطريقتين السابقتين لتحويل كائن Blob
إلى عنوان، لكن تكون عادةً الطريقة (URL.createObjectURL(blob
أبسط وأسرع.
Blob to data url | (URL.createObjectURL(blob |
---|---|
لا حاجة لإزالة أي شيء | لابد من إزالتها إذا كنا نهتم بمقدار الذاكرة المحجوزة |
خسارة في الأداء والذاكرة لكائنات Blob الضخمة عند الترميز
|
وصول مباشر إلى الكائن Blob ، لا حاجة للترميز وفك الترميز
|
تحويل الصورة إلى كائن Blob
يمكن تحويل صورة أو جزء من صورة أو لقطة شاشة إلى كائن بيانات ثنائية Blob
، وهذا مفيد عند تحميل هذه الصور إلى مكان ما، وتُنفّذ العمليات على الصور باستخدام العنصر <canvas>
:
- ارسم صورةً أو جزءًا منها ضمن لوحة الرسم Canvas باستخدام التابع canvas.drawImage.
- استدع التابع (toBlob(callback, format, quality الذي يُنشئ وينفّذ استدعاءً محددًا عندما يكتمل.
ستجد في المثال التالي صورةً نُسخت للتو، لكن يمكن اقتطاع جزء منها أو نقلها إلى لوحة رسم قبل إنشاء Blob
:
// خذ أية صورة let img = document.querySelector('img'); // شكّل لوحة رسم بنفس الحجم let canvas = document.createElement('canvas'); canvas.width = img.clientWidth; canvas.height = img.clientHeight; let context = canvas.getContext('2d'); // انسخ الصورة إلى اللوحة context.drawImage(img, 0, 0); // يمكن أن نعدل اللوحة كما نشاء // عملية التحويل إلى كائن ثنائي غير متزامنة canvas.toBlob(function(blob) { //الكائن جاهز سننزله let link = document.createElement('a'); link.download = 'example.png'; link.href = URL.createObjectURL(blob); link.click(); // امسح المرجع الداخلي للكائن حتى يتمكن Canvas المتصفح من إزالته URL.revokeObjectURL(link.href); }, 'image/png');
يمكن استخدام الصيغة async/await
بدلًا من دوال الاستدعاء:
let blob = await new Promise(resolve => canvasElem.toBlob(resolve, 'image/png'));
يمكن استخدام مكتبات خاصة لالتقاط صورة للشاشة، وما عليك إلا الانتقال ضمن الصفحة ورسمها ضمن لوحة <canvas>
، ثم يمكن نقلها بعد ذلك إلى Blob
بنفس الأسلوب السابق.
التحويل من الكائن Blob إلى الكائن arrayBuffer
تسمح الدالة البانية للكائن Blob
بإنشاء هذا الكائن من أي شيء تقريبًا، بما في ذلك أية كائنات BufferSource
، لكن لو أردنا إنجاز عملية معالجة منخفضة المستوى، فيمكننا الحصول على كائن ArrayBuffer
ذو مستوى أدنى مستخدمين FileReader
:
// get arrayBuffer from blob let fileReader = new FileReader(); fileReader.readAsArrayBuffer(blob); fileReader.onload = function(event) { let arrayBuffer = fileReader.result; };
خلاصة
-
تمثل الكائنات
ArrayBuffer
وUint8Array
وغيرها من الكائنات التي تنضوي تحت المصطلحBufferSource
بيانات ثنائيةً، بينما يمثل Blob بيانات ثنائيةً لها نوع، مما يجعل الكائنBlob
مناسبًا لعمليات الرفع والتنزيل التي تستخدم بكثرة من المتصفح. -
يمكن للتوابع التي تُنفِّذ طلبات الويب web-requests مثل: XMLHttpRequest وfetch وغيرها؛ أن تعمل مع
Blob
كما تعمل مع غيره من أنواع البيانات الثنائية. -
يمكن التحويل بسهولة بين
Blob
وكائنات البيانات الثنائية منخفضة المستوى: -
يمكن التحويل بين
Blob
ومصفوفة النوع باستخدام الدالة البانية(...)new Blob
-
يمكن الحصول على الكائن
ArrayBuffer
من الكائنBlob
باستخدام التعليمةFileReader
، ثم إنشاء كائن استعراض بناءً على هذا الأخير، وذلك لمعالجة البيانات الثنائية في مستويات عمل منخفضة.
ترجمة -وبتصرف- للفصل Blob من سلسلة The Modern JavaScript Tutorial.
اقرأ أيضًا
- المقال السابق: ترميز النصوص والتعامل مع كائنات الملفات في جافاسكريبت
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.