البيانات المستمرة عبر عمليات إعادة تحميل الصفحة: ملفات تعريف الارتباط وقاعدة بيانات مفهرسة وكل شيء بينهما

نشرت: 2022-03-11

افترض أنني أقوم بزيارة موقع ويب. أنقر بزر الماوس الأيمن على أحد روابط التنقل وحدد فتح الرابط في نافذة جديدة. ما ينبغي أن يحدث؟ إذا كنت مثل معظم المستخدمين ، أتوقع أن تحتوي الصفحة الجديدة على نفس المحتوى كما لو كنت قد قمت بالنقر فوق الارتباط مباشرة. يجب أن يكون الاختلاف الوحيد هو أن الصفحة تظهر في نافذة جديدة. ولكن إذا كان موقع الويب الخاص بك عبارة عن تطبيق من صفحة واحدة (SPA) ، فقد ترى نتائج غريبة ما لم تكن قد خططت بعناية لهذه الحالة.

تذكر أنه في SPA ، غالبًا ما يكون ارتباط التنقل النموذجي عبارة عن معرف جزء ، يبدأ بعلامة التجزئة (#). لا يؤدي النقر فوق الارتباط مباشرة إلى إعادة تحميل الصفحة ، لذلك يتم الاحتفاظ بجميع البيانات المخزنة في متغيرات JavaScript. ولكن إذا فتحت الرابط في علامة تبويب أو نافذة جديدة ، فإن المتصفح يعيد تحميل الصفحة ، ويعيد تهيئة جميع متغيرات جافا سكريبت. لذلك ستظهر أي عناصر HTML مرتبطة بهذه المتغيرات بشكل مختلف ، ما لم تتخذ خطوات للحفاظ على تلك البيانات بطريقة ما.

البيانات المستمرة عبر عمليات إعادة تحميل الصفحة: ملفات تعريف الارتباط وقاعدة بيانات مفهرسة وكل شيء بينهما

البيانات المستمرة عبر عمليات إعادة تحميل الصفحة: ملفات تعريف الارتباط وقاعدة بيانات مفهرسة وكل شيء بينهما
سقسقة

هناك مشكلة مماثلة إذا قمت بإعادة تحميل الصفحة صراحةً ، مثل الضغط على F5. قد تعتقد أنني لا يجب أن أضرب F5 أبدًا ، لأنك قمت بإعداد آلية لدفع التغييرات من الخادم تلقائيًا. ولكن إذا كنت مستخدمًا عاديًا ، فيمكنك الرهان على أنني ما زلت سأقوم بإعادة تحميل الصفحة. ربما يبدو أن متصفحي قد أعاد رسم الشاشة بشكل غير صحيح ، أو أريد فقط أن أتأكد من أن لدي أحدث أسعار الأسهم.

قد تكون واجهات برمجة التطبيقات عديمة الجنسية ، والتفاعل البشري ليس كذلك

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

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

مثال آخر هو محتويات عربة التسوق في موقع التجارة الإلكترونية. إذا أدى ضرب F5 إلى إفراغ عربة التسوق ، فمن المحتمل أن ينزعج المستخدمون.

في تطبيق تقليدي متعدد الصفحات مكتوب بلغة PHP ، سيتم تخزين بيانات الجلسة في مصفوفة superglobal $ _SESSION. ولكن في المنتجع الصحي ، يجب أن يكون في مكان ما بجانب العميل. هناك أربعة خيارات رئيسية لتخزين بيانات الجلسة في SPA:

  • بسكويت
  • معرّف الجزء
  • تخزين الويب
  • مفهرسة ديسيبل

أربعة كيلو بايت من ملفات تعريف الارتباط

ملفات تعريف الارتباط هي شكل قديم من أشكال تخزين الويب في المتصفح. كان الغرض منها في الأصل تخزين البيانات المستلمة من الخادم في طلب واحد وإرسالها مرة أخرى إلى الخادم في الطلبات اللاحقة. ولكن من JavaScript ، يمكنك استخدام ملفات تعريف الارتباط لتخزين أي نوع من البيانات ، بحد أقصى 4 كيلوبايت لكل ملف تعريف ارتباط. تقدم AngularJS وحدة ngCookies لإدارة ملفات تعريف الارتباط. هناك أيضًا حزمة ملفات تعريف الارتباط js التي توفر وظائف مماثلة في أي إطار عمل.

ضع في اعتبارك أن أي ملف تعريف ارتباط تقوم بإنشائه سيتم إرساله إلى الخادم عند كل طلب ، سواء كان ذلك إعادة تحميل صفحة أو طلب Ajax. ولكن إذا كانت بيانات الجلسة الرئيسية التي تريد تخزينها هي رمز الوصول للمستخدم الذي قام بتسجيل الدخول ، فأنت تريد إرسال هذا إلى الخادم عند كل طلب على أي حال. من الطبيعي أن تحاول استخدام ناقل الحركة التلقائي لملفات تعريف الارتباط هذا كوسيلة قياسية لتحديد رمز الوصول لطلبات Ajax.

قد تجادل بأن استخدام ملفات تعريف الارتباط بهذه الطريقة لا يتوافق مع بنية RESTful. ولكن في هذه الحالة ، يكون الأمر جيدًا لأن كل طلب عبر واجهة برمجة التطبيقات لا يزال عديم الحالة ، وله بعض المدخلات وبعض المخرجات. إنه فقط أن أحد المدخلات يتم إرساله بطريقة مضحكة ، عبر ملف تعريف ارتباط. إذا كان بإمكانك ترتيب طلب واجهة برمجة التطبيقات لتسجيل الدخول لإرسال رمز الوصول مرة أخرى في ملف تعريف الارتباط أيضًا ، فلن يحتاج رمز جانب العميل الخاص بك إلى التعامل مع ملفات تعريف الارتباط على الإطلاق. مرة أخرى ، إنه مجرد ناتج آخر من الطلب يتم إرجاعه بطريقة غير عادية.

تقدم ملفات تعريف الارتباط ميزة واحدة على تخزين الويب. يمكنك توفير مربع الاختيار "احتفظ بتسجيل الدخول" في نموذج تسجيل الدخول. باستخدام الدلالات ، أتوقع إذا تركتها بدون تحديد ، فسأظل مسجلاً للدخول إذا أعدت تحميل الصفحة أو فتحت رابطًا في علامة تبويب أو نافذة جديدة ، لكنني أضمن تسجيل الخروج بمجرد إغلاق المتصفح. هذه ميزة أمان مهمة إذا كنت أستخدم جهاز كمبيوتر مشتركًا. كما سنرى لاحقًا ، لا يدعم تخزين الويب هذا السلوك.

إذن كيف يمكن أن يعمل هذا النهج في الممارسة؟ افترض أنك تستخدم LoopBack على جانب الخادم. لقد قمت بتعريف نموذج الشخص ، وتوسيع نموذج المستخدم المضمن ، وإضافة الخصائص التي تريد الاحتفاظ بها لكل مستخدم. لقد قمت بتكوين نموذج الشخص ليتم عرضه عبر REST. أنت الآن بحاجة إلى تعديل server / server.js لتحقيق سلوك ملف تعريف الارتباط المطلوب. يوجد أدناه server / server.js ، بدءًا مما تم إنشاؤه بواسطة slc loopback ، بالتغييرات المحددة:

 var loopback = require('loopback'); var boot = require('loopback-boot'); var app = module.exports = loopback(); app.start = function() { // start the web server return app.listen(function() { app.emit('started'); var baseUrl = app.get('url').replace(/\/$/, ''); console.log('Web server listening at: %s', baseUrl); if (app.get('loopback-component-explorer')) { var explorerPath = app.get('loopback-component-explorer').mountPath; console.log('Browse your REST API at %s%s', baseUrl, explorerPath); } }); }; // start of first change app.use(loopback.cookieParser('secret')); // end of first change // Bootstrap the application, configure models, datasources and middleware. // Sub-apps like REST API are mounted via boot scripts. boot(app, __dirname, function(err) { if (err) throw err; // start of second change app.remotes().after('Person.login', function (ctx, next) { if (ctx.result.id) { var opts = {signed: true}; if (ctx.req.body.rememberme !== false) { opts.maxAge = 1209600000; } ctx.res.cookie('authorization', ctx.result.id, opts); } next(); }); app.remotes().after('Person.logout', function (ctx, next) { ctx.res.cookie('authorization', ''); next(); }); // end of second change // start the server if `$ node server.js` if (require.main === module) app.start(); });

يؤدي التغيير الأول إلى تكوين محلل ملفات تعريف الارتباط لاستخدام "السر" كسر توقيع ملف تعريف الارتباط ، وبالتالي تمكين ملفات تعريف الارتباط الموقعة. تحتاج إلى القيام بذلك لأنه على الرغم من أن LoopBack تبحث عن رمز وصول في أي من "تخويل" ملفات تعريف الارتباط أو "access_token" ، إلا أنها تتطلب توقيع ملف تعريف الارتباط هذا. في الواقع ، هذا المطلب لا طائل من ورائه. يهدف توقيع ملف تعريف الارتباط إلى ضمان عدم تعديل ملف تعريف الارتباط. ولكن ليس هناك خطر من قيامك بتعديل رمز الوصول. بعد كل شيء ، كان من الممكن أن ترسل رمز الوصول في شكل غير موقع ، كمعامل عادي. وبالتالي ، لا داعي للقلق بشأن صعوبة تخمين سر توقيع ملف تعريف الارتباط ، إلا إذا كنت تستخدم ملفات تعريف الارتباط الموقعة لشيء آخر.

يقوم التغيير الثاني بإعداد بعض المعالجة اللاحقة لطريقتي Person.login و Person.logout. بالنسبة إلى Person.login ، فأنت تريد أن تأخذ رمز الوصول الناتج وإرساله إلى العميل باعتباره "ترخيص" ملف تعريف الارتباط الموقع أيضًا. يمكن للعميل إضافة خاصية أخرى إلى معلمة بيانات الاعتماد ، تذكرني ، للإشارة إلى ما إذا كان يجب جعل ملف تعريف الارتباط مستمرًا لمدة أسبوعين. الافتراضي هو الصحيح. ستتجاهل طريقة تسجيل الدخول نفسها هذه الخاصية ، لكن المعالج اللاحق سيتحقق منها.

بالنسبة لـ Person.logout ، تريد مسح ملف تعريف الارتباط هذا.

يمكنك رؤية نتائج هذه التغييرات على الفور في StrongLoop API Explorer. عادةً بعد طلب Person.login ، سيتعين عليك نسخ رمز الوصول ولصقه في النموذج في الجزء العلوي الأيمن ، والنقر فوق تعيين رمز الوصول. لكن مع هذه التغييرات ، لا يتعين عليك القيام بأي من ذلك. يتم حفظ رمز الوصول تلقائيًا باعتباره "ترخيصًا" لملف تعريف الارتباط ، ويتم إرساله مرة أخرى في كل طلب لاحق. عندما يعرض المستكشف رؤوس الاستجابة من Person.login ، فإنه يحذف ملف تعريف الارتباط ، لأنه لا يُسمح لـ JavaScript مطلقًا برؤية رؤوس Set-Cookie. لكن كن مطمئنًا ، ملف تعريف الارتباط موجود.

من جانب العميل ، في إعادة تحميل الصفحة ، سترى ما إذا كان "ترخيص" ملف تعريف الارتباط موجودًا. إذا كان الأمر كذلك ، فأنت بحاجة إلى تحديث السجل الخاص بك لمعرّف المستخدم الحالي. ربما تكون أسهل طريقة للقيام بذلك هي تخزين معرف المستخدم في ملف تعريف ارتباط منفصل عند تسجيل الدخول بنجاح ، حتى تتمكن من استعادته عند إعادة تحميل الصفحة.

معرف الجزء

أثناء زيارتي لموقع ويب تم تنفيذه باعتباره SPA ، قد يبدو عنوان URL في شريط عنوان المتصفح الخاص بي مشابهًا لـ "https://example.com/#/my-photos/37". جزء معرف الجزء من هذا ، "# / my-photos / 37" ، هو بالفعل مجموعة من معلومات الحالة التي يمكن عرضها على أنها بيانات جلسة. في هذه الحالة ، ربما أشاهد إحدى صوري ، التي يبلغ هويتها 37.

قد تقرر تضمين بيانات جلسة أخرى في معرّف الجزء. تذكر أنه في القسم السابق ، مع رمز الوصول المخزن في "ترخيص" ملف تعريف الارتباط ، لا تزال بحاجة إلى تتبع معرف المستخدم بطريقة ما. أحد الخيارات هو تخزينه في ملف تعريف ارتباط منفصل. لكن هناك طريقة أخرى تتمثل في تضمينها في معرف الجزء. يمكنك أن تقرر أنه أثناء تسجيل الدخول ، ستحتوي جميع الصفحات التي أزورها على معرف جزء يبدأ بـ "# / u / XXX" ، حيث XXX هو معرف المستخدم. لذلك في المثال السابق ، قد يكون معرف الجزء هو "# / u / 59 / my-photos / 37" إذا كان معرف المستخدم الخاص بي هو 59.

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

ملاحظة أخيرة: من الممكن إعداد SPA بحيث لا تستخدم معرفات الأجزاء على الإطلاق. بدلاً من ذلك ، يستخدم عناوين URL عادية مثل "http://example.com/app/dashboard" و "http://example.com/app/my-photos/37" ، مع تهيئة الخادم لعرض HTML ذي المستوى الأعلى SPA ردًا على طلب لأي من عناوين URL هذه. ثم يقوم SPA الخاص بك بالتوجيه بناءً على المسار (على سبيل المثال "/ app / dashboard" أو "/ app / my-photos / 37") بدلاً من معرف الجزء. يعترض النقرات على روابط التنقل ، ويستخدم History.pushState () لدفع عنوان URL الجديد ، ثم يواصل التوجيه كالمعتاد. يستمع أيضًا إلى أحداث popstate لاكتشاف المستخدم الذي ينقر على زر الرجوع ، ويتابع مرة أخرى التوجيه على عنوان URL المستعاد. التفاصيل الكاملة لكيفية تنفيذ ذلك خارج نطاق هذه المقالة. ولكن إذا كنت تستخدم هذه التقنية ، فمن الواضح أنه يمكنك تخزين بيانات الجلسة في المسار بدلاً من معرف الجزء.

تخزين الويب

تخزين الويب هو آلية لجافا سكريبت لتخزين البيانات داخل المتصفح. مثل ملفات تعريف الارتباط ، تكون مساحة تخزين الويب منفصلة لكل أصل. كل عنصر مخزن له اسم وقيمة ، وكلاهما عبارة عن سلاسل. لكن تخزين الويب غير مرئي تمامًا للخادم ، ويوفر سعة تخزين أكبر بكثير من ملفات تعريف الارتباط. هناك نوعان من التخزين على الويب: التخزين المحلي وتخزين الجلسة.

يكون عنصر التخزين المحلي مرئيًا عبر جميع علامات التبويب في جميع النوافذ ، ويستمر حتى بعد إغلاق المتصفح. في هذا الصدد ، يتصرف إلى حد ما مثل ملف تعريف الارتباط مع تاريخ انتهاء الصلاحية بعيدًا جدًا في المستقبل. وبالتالي ، فهو مناسب لتخزين رمز وصول في حالة قيام المستخدم بفحص "الاحتفاظ بتسجيل الدخول" في نموذج تسجيل الدخول.

يكون عنصر تخزين الجلسة مرئيًا فقط داخل علامة التبويب حيث تم إنشاؤه ، ويختفي عند إغلاق علامة التبويب هذه. هذا يجعل عمرها مختلفًا تمامًا عن أي ملف تعريف ارتباط. تذكر أن ملف تعريف ارتباط الجلسة لا يزال مرئيًا عبر جميع علامات التبويب في جميع النوافذ.

إذا كنت تستخدم AngularJS SDK لـ LoopBack ، فسيستخدم جانب العميل تلقائيًا تخزين الويب لحفظ كل من رمز الوصول ومعرف المستخدم. يحدث هذا في خدمة LoopBackAuth في js / services / lb-services.js. سيستخدم التخزين المحلي ، ما لم تكن المعلمة RememberMe خاطئة (عادةً ما يعني أن مربع الاختيار "الاحتفاظ بتسجيل الدخول" لم يتم تحديده) ، وفي هذه الحالة سيستخدم تخزين الجلسة.

والنتيجة هي أنه إذا قمت بتسجيل الدخول مع عدم تحديد "الاحتفاظ بتسجيل الدخول" ، ثم قمت بفتح رابط في علامة تبويب أو نافذة جديدة ، فلن يتم تسجيل الدخول هناك. على الأرجح سأرى شاشة تسجيل الدخول. يمكنك أن تقرر بنفسك ما إذا كان هذا سلوكًا مقبولاً. قد يعتبرها البعض ميزة رائعة ، حيث يمكن أن يكون لديك عدة علامات تبويب ، كل منها قام بتسجيل الدخول كمستخدم مختلف. أو قد تقرر أنه لم يعد هناك أي شخص يستخدم أجهزة الكمبيوتر المشتركة بعد الآن ، لذلك يمكنك حذف مربع الاختيار "الاحتفاظ بتسجيل الدخول" تمامًا.

فكيف ستبدو معالجة بيانات الجلسة إذا قررت استخدام AngularJS SDK من أجل LoopBack؟ لنفترض أن لديك نفس الموقف كما كان من قبل على جانب الخادم: لقد حددت نموذج شخص ، وقمت بتوسيع نموذج المستخدم ، وقمت بعرض نموذج الشخص على REST. لن تستخدم ملفات تعريف الارتباط ، لذلك لن تحتاج إلى أي من التغييرات الموضحة سابقًا.

من جانب العميل ، في مكان ما في وحدة التحكم الخارجية ، من المحتمل أن يكون لديك متغير مثل $ range.currentUserId الذي يحمل معرف المستخدم للمستخدم المسجل حاليًا ، أو فارغًا إذا لم يكن المستخدم قد سجل الدخول. ثم للتعامل مع إعادة تحميل الصفحة بشكل صحيح ، فقط قم بتضمين هذه العبارة في دالة المُنشئ لوحدة التحكم هذه:

 $scope.currentUserId = Person.getCurrentId();

انه من السهل. أضف "شخص" كعنصر تبعية لوحدة التحكم الخاصة بك ، إذا لم تكن كذلك بالفعل.

مفهرسة ديسيبل

تعد IndexedDB وسيلة أحدث لتخزين كميات كبيرة من البيانات في المتصفح. يمكنك استخدامه لتخزين البيانات من أي نوع JavaScript ، مثل كائن أو مصفوفة ، دون الحاجة إلى إجراء تسلسل لها. جميع الطلبات لقاعدة البيانات غير متزامنة ، لذلك تحصل على رد عند اكتمال الطلب.

يمكنك استخدام قاعدة البيانات المفهرسة لتخزين البيانات المنظمة غير المرتبطة بأي بيانات على الخادم. قد يكون أحد الأمثلة التقويم أو قائمة المهام أو الألعاب المحفوظة التي يتم لعبها محليًا. في هذه الحالة ، يكون التطبيق محليًا حقًا ، وموقع الويب الخاص بك هو مجرد وسيلة لتقديمه.

في الوقت الحالي ، لا يدعم Internet Explorer و Safari سوى قاعدة بيانات مفهرسة جزئيًا. المتصفحات الرئيسية الأخرى تدعمه بشكل كامل. أحد القيود الخطيرة في الوقت الحالي ، على الرغم من ذلك ، هو أن Firefox يعطل IndexedDB تمامًا في وضع التصفح الخاص.

كمثال ملموس على استخدام IndexedDB ، دعنا نأخذ تطبيق الألغاز المنزلق بواسطة Pavol Daniš ، ونقوم بتعديله لحفظ حالة اللغز الأول ، وهو اللغز الأساسي 3x3 المنزلق على أساس شعار AngularJS ، بعد كل حركة. ستؤدي إعادة تحميل الصفحة بعد ذلك إلى استعادة حالة هذا اللغز الأول.

لقد قمت بإعداد مفترق للمستودع مع هذه التغييرات ، وكلها موجودة في app / js / Puzzle / slidingPuzzle.js. كما ترى ، حتى الاستخدام البدائي لـ IndexedDB هو أمر مهم. سأعرض فقط النقاط البارزة أدناه. أولاً ، يتم استدعاء استعادة الوظيفة أثناء تحميل الصفحة ، لفتح قاعدة بيانات IndexedDB:

 /* * Tries to restore game */ this.restore = function(scope, storekey) { this.storekey = storekey; if (this.db) { this.restore2(scope); } else if (!window.indexedDB) { console.log('SlidingPuzzle: browser does not support indexedDB'); this.shuffle(); } else { var self = this; var request = window.indexedDB.open('SlidingPuzzleDatabase'); request.onerror = function(event) { console.log('SlidingPuzzle: error opening database, ' + request.error.name); scope.$apply(function() { self.shuffle(); }); }; request.onupgradeneeded = function(event) { event.target.result.createObjectStore('SlidingPuzzleStore'); }; request.onsuccess = function(event) { self.db = event.target.result; self.restore2(scope); }; } };

يعالج الحدث request.onupgradeneeded الحالة التي لا توجد فيها قاعدة البيانات بعد. في هذه الحالة ، نقوم بإنشاء ملف تخزين العناصر.

بمجرد فتح قاعدة البيانات ، يتم استدعاء وظيفة الاستعادة 2 ، والتي تبحث عن سجل بمفتاح معين (والذي سيكون في الواقع الثابت "أساسي" في هذه الحالة):

 /* * Tries to restore game, once database has been opened */ this.restore2 = function(scope) { var transaction = this.db.transaction('SlidingPuzzleStore'); var objectStore = transaction.objectStore('SlidingPuzzleStore'); var self = this; var request = objectStore.get(this.storekey); request.onerror = function(event) { console.log('SlidingPuzzle: error reading from database, ' + request.error.name); scope.$apply(function() { self.shuffle(); }); }; request.onsuccess = function(event) { if (!request.result) { console.log('SlidingPuzzle: no saved game for ' + self.storekey); scope.$apply(function() { self.shuffle(); }); } else { scope.$apply(function() { self.grid = request.result; }); } }; }

في حالة وجود مثل هذا السجل ، تحل قيمته محل مجموعة الشبكة للغز. إذا كان هناك أي خطأ في استعادة اللعبة ، فنحن نخلط المربعات كما كان من قبل. لاحظ أن الشبكة عبارة عن صفيف 3x3 من كائنات البلاط ، كل منها معقد إلى حد ما. الميزة العظيمة لـ IndexedDB هي أنه يمكنك تخزين واسترجاع هذه القيم دون الحاجة إلى تسلسلها.

نستخدم تطبيق $ لإبلاغ AngularJS بتغيير النموذج ، لذلك سيتم تحديث العرض بشكل مناسب. هذا لأن التحديث يحدث داخل معالج أحداث DOM ، لذلك لن تتمكن AngularJS من اكتشاف التغيير. من المحتمل أن يحتاج أي تطبيق AngularJS يستخدم IndexedDB إلى استخدام تطبيق $ لهذا السبب.

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

 /* * Tries to save game */ this.save = function() { if (!this.db) { return; } var transaction = this.db.transaction('SlidingPuzzleStore', 'readwrite'); var objectStore = transaction.objectStore('SlidingPuzzleStore'); var request = objectStore.put(this.grid, this.storekey); request.onerror = function(event) { console.log('SlidingPuzzle: error writing to database, ' + request.error.name); }; request.onsuccess = function(event) { // successful, no further action needed }; }

التغييرات المتبقية هي استدعاء الوظائف المذكورة أعلاه في الأوقات المناسبة. يمكنك مراجعة الالتزام بإظهار كافة التغييرات. لاحظ أننا نطلب الاستعادة للغز الأساسي فقط ، وليس للألغاز الثلاثة المتقدمة. نحن نستغل حقيقة أن الألغاز الثلاثة المتقدمة لها سمة API ، لذلك بالنسبة لأولئك الذين نقوم فقط بالخلط العادي.

ماذا لو أردنا حفظ الألغاز المتقدمة واستعادتها أيضًا؟ سيتطلب ذلك بعض إعادة الهيكلة. في كل من الألغاز المتقدمة ، يمكن للمستخدم ضبط ملف مصدر الصورة وأبعاد اللغز. لذلك علينا تحسين القيمة المخزنة في قاعدة البيانات المفهرسة لتضمين هذه المعلومات. الأهم من ذلك ، أننا نحتاج إلى طريقة لتحديثها من الاستعادة. هذا كثير قليلاً بالنسبة لهذا المثال الطويل بالفعل.

خاتمة

في معظم الحالات ، يعد التخزين على الويب هو أفضل رهان لتخزين بيانات الجلسة. إنها مدعومة بالكامل من قبل جميع المتصفحات الرئيسية ، وتوفر سعة تخزين أكبر بكثير من ملفات تعريف الارتباط.

يمكنك استخدام ملفات تعريف الارتباط إذا تم إعداد الخادم الخاص بك بالفعل لاستخدامها ، أو إذا كنت بحاجة إلى إمكانية الوصول إلى البيانات عبر جميع علامات التبويب في جميع النوافذ ، ولكنك تريد أيضًا التأكد من حذفها عند إغلاق المتصفح.

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

من المحتمل أن يتطلب استخدام IndexedDB ترميزًا أكثر بكثير من أي من الأساليب الأخرى. ولكن إذا كانت القيم التي تقوم بتخزينها عبارة عن كائنات جافا سكريبت معقدة يصعب إجراء تسلسل لها ، أو إذا كنت بحاجة إلى نموذج معاملات ، فقد يكون ذلك مفيدًا.