تقدم المتصفحات الحديثة مجموعة من التقنيات المختلفة التي تسمح بتخزين بيانات تتعلق بمواقع الويب ثم استرجاعها عند الضرورة، مما يسمح لنا بالحفاظ على البيانات لفترة أطول أو تخزينها للعمل دون اتصال باﻹنترنت وغير ذلك. لهذا سنناقش في مقالنا أبسط اﻷساسيات المتعلقة بهذا اﻷمر وكيفية عملها.
ننصحك قبل المتابعة في قراءة هذه المقالات أن:
- تكون ملمًا بلغتي HTML و CSS.
- تكون ملمًا بلغة جافا سكريبت.
- تطلع على سلاسل المقالات السابقة التي ناقشت أساسيات جافا سكريبت والكائنات في جافا سكريبت.
- تطلع على أساسيات الواجهات البرمجية في طرف العميل.
ماذا يعني تخزين البيانات في طرف العميل؟
تحدثنا في مقالات مختلفة عن الفرق بين مواقع الويب الساكنة والدينياميكية، لكن لا بد من اﻹشارة إلى أن معظم مواقع الويب الحديثة ديناميكية، فهي تخزن البيانات في الخادم مستخدمة نوعًا من قواعد البيانات (تخزين في طرف الخادم)، ومن ثم تنفّذ شيفرة في طرف الخادم لاستعادتها ووضعها ضمن قوالب صفحات ساكنة، لتقدّم النتيجة بعدها إلى العميل على شكل صفحاتHTML يعرضها المتصفح.
ويعمل التخزين في طرف العميل وفق اﻷسلوب ذاته، لكن له استخدامات خاصة. ولتنفيذ هذه العمليات نحتاج إلى واجهات جافا سكريبت التي تسمح لنا بتخزين البيانات على جهاز العميل واستعادتها عند الحاجة. وتُخّزن البيانات في طرف العميل لاستخدامات محددة مثل:
- إضفاء خصوصية للمستخدم في الموقع (مثل عرض خيارات يفضلها المستخدم أو اختيار اللون أو حجم الخط).
- تخزين النشاطات السابقة للمستخدم مثل تخزين محتوى قائمة مشتريات من جلسة سابقة أو تذكر تسجيل الدخول السابق).
- تخزين البيانات واﻷصول محليًا لتسريع تحميل الموقع (مع احتمال انخفاض كلفة التصفح) وإمكانية التصفح دون الاتصال بالانترنت.
- تخزين صفحات الويب التي تولدها تطبيقات الويب ديناميكيًا محليًا لاستخدامها دون اتصال بالانترنت.
تُستخدم الطريقتان السابقتان في التخزين معًا عادةً، فقد تحمّل مثلًا ملف موسيقى (يُستخدم مع لعبة ويب أو مشغّل موسيقى) ومن ثم تخزّنه في قاعدة بيانات طرف العميل ومن ثم تشغيله عند الحاجة. وهكذا يمكن للمستخدم تحميل الملف لمرة واحدة، وعند الزيارات اللاحقة للموقع يستخرج الملف من قاعدة بياناته المحلية مما يسرع العملية ويقلل تكلفة التصفح.
ملاحظة: هناك حد لكمية البيانات التي يمكن تخزينها في طرف العميل عبر الواجهات البرمجية (منفصلة أو مجتمعة) ويختلف هذا الحد وفقًا للمتصفح، وقد يعتمد على اﻹعدادات التي يضبطها المستخدم.
استخدام الطريقة التقليدية: ملفات تعريف الارتباط Cookies
تُعد تقنية تخزين البيانات في طرف العميل تقنية قديمة، فقد استخدمت المواقع ملفات تعريف الارتباط cookies منذ البدايات الأولى للويب، وذلك لتخزين البيانات وإعطاء طابع شخصي للموقع. وقد كانت أولى أشكال تخزين البيانات في طرف العميل.
أما حاليًا، فقد ظهرت تقنيات أفضل وأحدث لتخزين البيانات في طرف العميل، لذلك لن نتحدث عن استخدام ملفات تعريف اﻹرتباط في مقالنا الحالي. ولا يعني ذلك بالطبع أن ملفات تعريف الارتباط عديمة الفائدة في عالم الويب المعاصر، إذ لا تزال شائعة الاستخدام في تخزين البيانات المتعلقة بمعلومات المستخدم الشخصية وحالته مثل معرفات الجلسة session IDs ومفاتيح الوصول المشفرة access token.
التقنية الجديدة: مخازن ويب وقاعدة البيانات IndexedDB
من الميزات السهلة للتقنيتين اللتين يشير إليهما العنوان نجد:
- اﻵلية التي تقدمها واجهة مخازن ويب البرمجية Web Storage API في تخزين واسترجاع عناصر البيانات صغيرة الحجم والمكونة من اسم وقيمة موافقة. ولهذا اﻷمر أهميته عندما تحتاج إلى تخزين بيانات بسيطة مثل اسم المستخدم وتاريخ تسجيل الدخول إلى موقع الويب واللون الذي يفضله للخلفية وهكذا.
- قاعدة البيانات المتكاملة التي تقدمها الواجهة البرمجية IndexedDB API للمتصفح لتخزين البيانات الأكثر تعقيدًا. يمكن استخدام هذه القاعدة مثلًا في تخزين بيانات مجموعة كاملة من سجلات المستخدمين وحتى أنواع معقدة من البيانات مثل ملفات الصوت والفيديو.
الواجهة البرمجية Cache
صُممت هذه الواجهة لتحزين الاستجابات الناتجة عن طلبات HTTP محددة، وهي مفيدة خصوصًا في أمور مثل تخزين أصول موقع ويب محليًا ليتمكن الموقع من استخدامها باستمرار دون اتصال مع شبكة اﻹنترنت. تُستخدم واجهة التخزين المؤقت cache
عادةً بمرافقة واجهة عمال الخدمة Service Worker API على الرغم من عدم الحاجة إلى ذلك فعليًا.
ويُعد استخدام واجهة التخزين المؤقت مع واجهة عمال الخدمة موضوعًا متقدمًا لن نغطيه في سلسلة مقالاتنا بالتفصيل، مع ذلك، سنعرض في آخر مقال من هذه السلسلة مثالًا عنها.
الواجهة Web Storage
وتخزين بيانات بسيطة
من السهل جدًا استخدام هذه الواجهة، إذ تخزن البيانات البسيطة على شكل أزواج مكونة من اسم name وقيمة value (محدودة بأنواع مخصصة مثل النصوص واﻷعداد وغيرها)، ومن ثم استرجاع تلك القيم عند الحاجة.
الصياغة القواعدية الأساسية
لنلق نظرة على ذلك:
- انتقل بداية إلى القالب الموجود على جيت-هاب وافتحه في نافذة جديدة.
- افتح طرفية جافا سكريبت في المتصفح.
-
توضع مخازن ويب ضمن بُنى تشبه الكائنات في المتصفح هي
sessionStorge
وlocalStorage
. تبقى البيانات المخزنة في البنية اﻷولى طالما أن المتصفح يعمل (تُحذف هذه البيانات عند إغلاق المتصفح)، بينما تبقى البيانات في البنية الثانية مقيمة في الذاكرة حتى بعد إغلاق المتصفح. سنستخدم في مقالنا البنية الثانية لأنها أكثر فائدة عمومًا. إذ يسمح التابع()Strorage.setItem
بتخزين البيانات في البنية Storge، وله معاملان: اﻷول هو اسم العنصر، والثاني هو القيمة. جرّب كتابة ما يلي في طرفية جافا سكريبت:
localStorage.setItem("name", "Chris");
-
يأخذ التابع
()Storage.getItem
معاملًا واحدًا يمثل عنصر البيانات الذي تريد استرجاع قيمته. جرّب اﻵن الشيفرة التالية:
let myName = localStorage.getItem("name"); myName;
سترى عند كتابتك الشيفرة السابقة كيف سيضم المتغير myName
قيمة عنصر البيانات name
.
-
يأخذ التابع
()removeItem
معاملًا واحدًا هو اسم عنصر البيانات التي تريد إزالته ومن ثم يزيله من مخزن ويب. جرّب الشيفرة التالية في طرفية جافا سكريبت:
localStorage.removeItem("name"); myName = localStorage.getItem("name"); myName;
من المفترض أن يعيد تنفيذ السطر الثالث القيمة null
للعنصر name
لأنه لم يعد موجودًا في مخزن ويب.
البيانات المقيمة في الذاكرة
من الميزات المهمة لمخازن ويب أن البيانات تبقى موجودة في الفترة التي تُحمّل فيها الصفحات وحتى بعد إغلاق المتصفح عند استخدام local Storage
، لنلق نظرة على هذا اﻷمر:
- افتح مجددًا قالب مخازن ويب السابق لكن في متصفح يختلف عن المتصفح الذي تقرأ فيه هذا المقال.
- اكتب الشيفرة التالية في طرفية جافا سكريبت لهذا المتصفح:
localStorage.setItem("name", "Chris"); let myName = localStorage.getItem("name"); myName;
من المفترض أن ترى قيمة عنصر البيانات name
.
- اغلق اﻵن المتصفح ثم افتحه مجددًا.
- اكتب الشيفرة التالية في طرفية جافا سكريبت:
let myName = localStorage.getItem("name"); myName;
سترى أن قيمة عنصر البيانات لا تزال متوفرة على الرغم من إغلاق المتصفح وفتحه مجددًا.
مخزن منفصل لكل نطاق
يُوجد مخزن بيانات منفصل لكل نطاق (لكل عنوان ويب حمّله المتصفح)، وسترى ذلك إن حمّلت موقعين وحاولت تخزين عنصر بيانات في أحدهما، فلن يكون هذا العنصر متاحًا للموقع اﻵخر. وهذا اﻷمر منطقي، فرؤية بيانات موقع من موقع آخر مصدر للكثير من الثغرات اﻷمنية.
مثال على مخزن ويب بتفاصيل أكثر
سنبني في هذه الفقرة مثالًا نطبق فيه ما تعلمناه ويعطيك فكرة عن كيفية استخدام مخزن ويب. ندخل في هذا المثال اسمًا ثم نُحدّث الصفحة بعد ذلك لترحب بصاحب الاسم شخصيًا. وستبقى هذه الحالة خلال إعادة تحميل الصفحات أو المتصفح لأننا سنخزن الاسم في مخزن ويب.
بإمكانك إيجاد نسخة عن ملف HTML المستخدم على جيت-هاب، ويتضمن موقع ويب يتكون من ترويسة ومحتوى وتذييل ونموذج ﻹدخال الاسم.
سنبني المثال اﻵن حتى نفهم آلية عمله:
- انسخ ملف المثال إلى مجلد على حاسوبك.
-
لاحظ كيف يشير ملف HTML إلى ملف جافا سكريبت يُدعى
index.js
من خلال سطر يشبه السطر
<script src="index.js" defer></script>
.
علينا إذًا إنشاء الملفindex.js
ضمن نفس المجلد الذي يضم ملف HTML وكتابة شيفرة جافا سكريبت ضمنه. - نبدأ الشيفرة ببناء مراجع إلى جميع عناصر HTML التي نريد التعامل معها في مثالنا، وستكون هذه المراجع على شكل ثوابت لأننا لن نغيرها خلال دورة حياة التطبيق. أضف اﻵن الشيفرة التالية:
// إنشاء الثوابت المطلوبة const rememberDiv = document.querySelector(".remember"); const forgetDiv = document.querySelector(".forget"); const form = document.querySelector("form"); const nameInput = document.querySelector("#entername"); const submitBtn = document.querySelector("#submitname"); const forgetBtn = document.querySelector("#forgetname"); const h1 = document.querySelector("h1"); const personalGreeting = document.querySelector(".personal-greeting");
- علينا اﻵن كتابة مترصد أحداث بسيط لمنع النموذج من تسليم محتوياته عند النقر على زر اﻹرسال، فهذا ليس السلوك الذي نريده. أضف الشيفرة التالية تحت الشيفرة السابقة:
// Stop the form from submitting when a button is pressed form.addEventListener("submit", (e) => e.preventDefault());
-
يجب إضافة الدالة التي تتعامل مع حدث النقر على الزر "Say hello"، وستجد شرحًا وافيًا ضمن تعليقات الشيفرة لكل خطوة، لكن ما تفعله الشيفرة عمومًا هو الحصول على الاسم الذي ندخله ضمن صندوق اﻹدخال النصي وتخزينه في مخزن ويب باستخدام الدالة
()setItem
ثم تنفيذ الدالة()nameDisplayCheck
التي تعالج عملية تحديث النص المطلوب من الصفحة. أضف الشيفرة التالية أسفل الشيفرة السابقة:
//`Say hello` نفذ الدالة عند النقر على الزر submitBtn.addEventListener("click", () => { // احفظ الاسم في مخزن ويب localStorage.setItem("name", nameInput.value); //لعرض التحية المخصصة nameDisplayCheck استخدم الدالة nameDisplayCheck(); });
-
نحتاج إلى معالج حدث للتعامل مع النقر على الزر "Forget" الذي يظهر فقط بعد النقر على الزر "Say hello". كما نزيل في دالة معالج الحدث العنصر
name
من مخزن ويب باستخدام التابع()removeItem
ثم ننفذ مجددًا الدالة()nameDisplayCheck
لتحديث ما يُعرض. أضف الآن الشيفرة التالية:
//`Forget` نفّذ الدالة عند النقر على الزر forgetBtn.addEventListener("click", () => { //إزالة الاسم المخزن في مخزن ويب localStorage.removeItem("name"); //لعرض التحية الأصلية وتحديث ما يُعرض nameDisplayCheck استخدم الدالة nameDisplayCheck(); });
-
نعرّف اﻵن الدالة
()nameDisplayCheck
التي نتحقق فيها فيما لو خُزِّن العنصرname
في مخزن ويب باستخدام التابع('name('localStorage.getItem
من خلال عبارة شرطية. فإن وُجد في المخزن، ستكون نتيجة الشرطtrue
وإلا ستكونfalse
. نعرض في الحالة اﻷولى رسالة الترحيب الخاصة ونعرض الجزء "forget" من النموذج ونخفي الجزء "Say hello"، أما في الحالة الثانية، سنعرض الرسالة الأصلية ونجري عكس ما فعلناه في الحالة الأولى:
// nameDisplayCheck() نعرّف الدالة function nameDisplayCheck() { // نتحقق من تخزين عنصر الاسم في مخزن ويب if (localStorage.getItem("name")) { // نعرض رسالة الترحيب المخصصة إن كان الأمر كذلك const name = localStorage.getItem("name"); h1.textContent = `Welcome, ${name}`; personalGreeting.textContent = `Welcome to our website, ${name}! We hope you have fun while you are here.`; //`forget` من الاستمارة ونعرض الجزء `remember` نخفي الجزء forgetDiv.style.display = "block"; rememberDiv.style.display = "none"; } else { // إن لم يكن الايم مخزنًانعرض الرسالة اﻷصلية h1.textContent = "Welcome to our website "; personalGreeting.textContent = "Welcome to our website. We hope you have fun while you are here."; //`remember` من الاستمارة ونعرض الجزء `forget` نخفي الجزء forgetDiv.style.display = "none"; rememberDiv.style.display = "block"; } }
-
ننفذ الدالة
()nameDisplayCheck
عند اكتمال تحميل الصفحة. لأن الرسالة المخصصة لن تظهر إن لم نفعل ذلك خلال تحميل الصفحة بشكل متكرر. أضف ما يلي إلى آخر الشيفرة:
nameDisplayCheck();
وهكذا يكون مثالنا قد انتهي، وبإمكان الاطلاع في أي وقت على النسخة المكتملة منه على جيت-هاب.
ملاحظة: تمنع السمة defer
في السطر التالي من تنفيذ شيفرة جافا سكريبت حتى اكتمال تحميل الصفحة
<script src="index.js" defer></script>
.
الخلاصة
تعرفنا في هذا المقال على أساسيات تخزين البيانات في طرف العميل من خلال واجهات برمجية مخصصة مثل Web Storage API و IndexedDB. كما شرحنا مخازن ويب Web Storage وطريقة العمل معها من خلال مثال تطبيقي بسيط يعرض أساسيات العمل مع هذه الواجهة البرمجية.
ترجمة -وبتصرف- للجزء الأول من مقال: Client-side storage
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.