একটি কঠিন অফলাইন অভিজ্ঞতা তৈরি করতে, আপনার PWA স্টোরেজ ব্যবস্থাপনার প্রয়োজন। ক্যাশিং অধ্যায়ে আপনি শিখেছেন যে ক্যাশে স্টোরেজ একটি ডিভাইসে ডেটা সংরক্ষণ করার একটি বিকল্প। এই অধ্যায়ে, আমরা আপনাকে দেখাব কিভাবে অফলাইন ডেটা পরিচালনা করতে হয়, যার মধ্যে ডেটা স্থিরতা, সীমা এবং উপলব্ধ সরঞ্জামগুলি রয়েছে৷
স্টোরেজ
সঞ্চয়স্থান শুধুমাত্র ফাইল এবং সম্পদ সম্পর্কে নয়, কিন্তু অন্যান্য ধরনের ডেটা অন্তর্ভুক্ত করতে পারে। PWA সমর্থন করে এমন সমস্ত ব্রাউজারে, ডিভাইসে স্টোরেজের জন্য নিম্নলিখিত APIগুলি উপলব্ধ:
- IndexedDB : স্ট্রাকচার্ড ডেটা এবং ব্লবসের (বাইনারী ডেটা) জন্য একটি NoSQL অবজেক্ট স্টোরেজ বিকল্প।
- WebStorage: স্থানীয় স্টোরেজ বা সেশন স্টোরেজ ব্যবহার করে কী/মান স্ট্রিং জোড়া সঞ্চয় করার একটি উপায়। এটি একটি পরিষেবা কর্মী প্রসঙ্গে উপলব্ধ নয়৷ এই APIটি সিঙ্ক্রোনাস তাই জটিল ডেটা স্টোরেজের জন্য এটি সুপারিশ করা হয় না।
- ক্যাশে স্টোরেজ: ক্যাশিং মডিউলে কভার করা হয়েছে।
আপনি সমর্থিত প্ল্যাটফর্মগুলিতে স্টোরেজ ম্যানেজার API এর মাধ্যমে সমস্ত ডিভাইস স্টোরেজ পরিচালনা করতে পারেন। ক্যাশে স্টোরেজ এপিআই এবং ইনডেক্সডডিবি পিডব্লিউএ-এর জন্য অবিরাম স্টোরেজ অ্যাসিঙ্ক্রোনাস অ্যাক্সেস প্রদান করে এবং প্রধান থ্রেড, ওয়েব কর্মী এবং পরিষেবা কর্মীদের থেকে অ্যাক্সেস করা যেতে পারে। উভয়ই পিডব্লিউএ-কে নির্ভরযোগ্যভাবে কাজ করার ক্ষেত্রে অপরিহার্য ভূমিকা পালন করে যখন নেটওয়ার্কটি ফ্ল্যাকি বা অস্তিত্বহীন থাকে। কিন্তু যখন আপনি প্রতিটি ব্যবহার করা উচিত?
নেটওয়ার্ক সংস্থানগুলির জন্য ক্যাশে স্টোরেজ API ব্যবহার করুন, যে জিনিসগুলি আপনি একটি URL এর মাধ্যমে অনুরোধ করে অ্যাক্সেস করতে চান, যেমন HTML, CSS, JavaScript, ছবি, ভিডিও এবং অডিও৷
স্ট্রাকচার্ড ডেটা সঞ্চয় করতে IndexedDB ব্যবহার করুন। এর মধ্যে এমন ডেটা রয়েছে যা NoSQL-এর মতো পদ্ধতিতে অনুসন্ধানযোগ্য বা একত্রিত করা প্রয়োজন, বা অন্যান্য ডেটা যেমন ব্যবহারকারী-নির্দিষ্ট ডেটা যা অগত্যা একটি URL অনুরোধের সাথে মেলে না। মনে রাখবেন যে IndexedDB সম্পূর্ণ-টেক্সট অনুসন্ধানের জন্য ডিজাইন করা হয়নি।
ইনডেক্সডডিবি
IndexedDB ব্যবহার করতে, প্রথমে একটি ডাটাবেস খুলুন। এটি একটি নতুন ডাটাবেস তৈরি করে যদি একটি বিদ্যমান না থাকে। IndexedDB একটি অ্যাসিঙ্ক্রোনাস API, কিন্তু এটি একটি প্রতিশ্রুতি ফেরত দেওয়ার পরিবর্তে একটি কলব্যাক নেয়। নিচের উদাহরণে Jake Archibald's idb লাইব্রেরি ব্যবহার করা হয়েছে, যা IndexedDB-এর জন্য একটি ক্ষুদ্র, প্রতিশ্রুতিবদ্ধ মোড়ক। IndexedDB ব্যবহার করার জন্য হেল্পার লাইব্রেরিগুলির প্রয়োজন নেই, তবে আপনি যদি প্রতিশ্রুতি সিনট্যাক্স ব্যবহার করতে চান তবে idb
লাইব্রেরি একটি বিকল্প।
নিম্নলিখিত উদাহরণটি রান্নার রেসিপিগুলি ধরে রাখার জন্য একটি ডাটাবেস তৈরি করে।
একটি ডাটাবেস তৈরি এবং খোলা
একটি ডাটাবেস খুলতে:
- একটি নতুন IndexedDB ডাটাবেস তৈরি করতে
openDB
ফাংশন ব্যবহার করুন যাকেcookbook
বলা হয়। যেহেতু IndexedDB ডাটাবেসগুলি সংস্করণ করা হয়েছে, আপনি যখনই ডাটাবেস কাঠামোতে পরিবর্তন করবেন তখনই আপনাকে সংস্করণ নম্বর বাড়াতে হবে। দ্বিতীয় প্যারামিটারটি ডাটাবেস সংস্করণ। উদাহরণে 1 সেট করা আছে। - একটি
upgrade()
কলব্যাক ধারণকারী একটি প্রারম্ভিক বস্তুopenDB()
এ পাস করা হয়। কলব্যাক ফাংশন বলা হয় যখন ডাটাবেস প্রথমবার ইনস্টল করা হয় বা যখন এটি একটি নতুন সংস্করণে আপগ্রেড হয়। এই ফাংশনটি একমাত্র জায়গা যেখানে কর্ম ঘটতে পারে। ক্রিয়াকলাপের মধ্যে নতুন অবজেক্ট স্টোর তৈরি করা অন্তর্ভুক্ত থাকতে পারে (ডাটা সংগঠিত করার জন্য IndexedDB যে কাঠামো ব্যবহার করে), বা সূচীগুলি (যেটি আপনি অনুসন্ধান করতে চান)। এখানেও ডেটা মাইগ্রেশন হওয়া উচিত। সাধারণত,upgrade()
ফাংশনে একটিswitch
স্টেটমেন্ট থাকেbreak
স্টেটমেন্ট ছাড়াই প্রতিটি ধাপকে ক্রমানুসারে ঘটতে দেয়, ডাটাবেসের পুরানো সংস্করণের উপর ভিত্তি করে।
import { openDB } from 'idb';
async function createDB() {
// Using https://github.com/jakearchibald/idb
const db = await openDB('cookbook', 1, {
upgrade(db, oldVersion, newVersion, transaction) {
// Switch over the oldVersion, *without breaks*, to allow the database to be incrementally upgraded.
switch(oldVersion) {
case 0:
// Placeholder to execute when database is created (oldVersion is 0)
case 1:
// Create a store of objects
const store = db.createObjectStore('recipes', {
// The `id` property of the object will be the key, and be incremented automatically
autoIncrement: true,
keyPath: 'id'
});
// Create an index called `name` based on the `type` property of objects in the store
store.createIndex('type', 'type');
}
}
});
}
উদাহরণটি cookbook
ডাটাবেসের ভিতরে recipes
নামে একটি বস্তুর দোকান তৈরি করে, id
প্রপার্টিটি স্টোরের ইনডেক্স কী হিসাবে সেট করে এবং type
প্রপার্টির উপর ভিত্তি করে type
নামে আরেকটি সূচক তৈরি করে।
আসুন অবজেক্ট স্টোরটি দেখে নেওয়া যাক যা এইমাত্র তৈরি করা হয়েছে। অবজেক্ট স্টোরে রেসিপি যোগ করার পরে এবং ক্রোমিয়াম-ভিত্তিক ব্রাউজারে বা Safari-তে ওয়েব ইন্সপেক্টরে DevTools খোলার পরে, আপনার এটি দেখার আশা করা উচিত:
ডেটা যোগ করা হচ্ছে
IndexedDB লেনদেন ব্যবহার করে। লেনদেনগুলি একসাথে কাজ করে, তাই সেগুলি একটি ইউনিট হিসাবে ঘটে। তারা নিশ্চিত করতে সাহায্য করে যে ডাটাবেস সবসময় একটি সামঞ্জস্যপূর্ণ অবস্থায় থাকে। একই ডেটাতে একযোগে লেখা রোধ করার জন্য যদি আপনার অ্যাপের একাধিক কপি চলমান থাকে তবে সেগুলিও সমালোচনামূলক। ডেটা যোগ করতে:
-
readwrite
সেট করাmode
দিয়ে একটি লেনদেন শুরু করুন। - অবজেক্ট স্টোর পান, যেখানে আপনি ডেটা যোগ করবেন।
- আপনি যে ডেটা সংরক্ষণ করছেন তার সাথে
add()
কল করুন। পদ্ধতিটি অভিধান আকারে ডেটা গ্রহণ করে (কী/মান জোড়া হিসাবে) এবং এটি অবজেক্ট স্টোরে যোগ করে। স্ট্রাকচার্ড ক্লোনিং ব্যবহার করে অভিধানটি অবশ্যই ক্লোনযোগ্য হতে হবে। আপনি যদি একটি বিদ্যমান বস্তু আপডেট করতে চান, তাহলে আপনি পরিবর্তেput()
পদ্ধতিতে কল করবেন।
লেনদেনের একটি done
প্রতিশ্রুতি আছে যা লেনদেন সফলভাবে সম্পন্ন হলে, বা লেনদেনের ত্রুটির সাথে প্রত্যাখ্যান করলে সমাধান হয়।
যেমন IDB লাইব্রেরি ডকুমেন্টেশন ব্যাখ্যা করে, আপনি যদি ডাটাবেসে লিখছেন, tx.done
হল সিগন্যাল যে সবকিছু সফলভাবে ডাটাবেসের জন্য প্রতিশ্রুতিবদ্ধ। যাইহোক, পৃথক ক্রিয়াকলাপের জন্য অপেক্ষা করা উপকারী যাতে আপনি লেনদেন ব্যর্থ হওয়ার কারণ হতে পারে এমন কোনো ত্রুটি দেখতে পান।
// Using https://github.com/jakearchibald/idb
async function addData() {
const cookies = {
name: "Chocolate chips cookies",
type: "dessert",
cook_time_minutes: 25
};
const tx = await db.transaction('recipes', 'readwrite');
const store = tx.objectStore('recipes');
store.add(cookies);
await tx.done;
}
একবার আপনি কুকিজ যোগ করলে, রেসিপিটি অন্যান্য রেসিপির সাথে ডাটাবেসে থাকবে। ID স্বয়ংক্রিয়ভাবে সেট করা হয় এবং indexedDB দ্বারা বৃদ্ধি পায়। আপনি যদি এই কোডটি দুবার চালান তবে আপনার কাছে দুটি অভিন্ন কুকি এন্ট্রি থাকবে।
ডেটা পুনরুদ্ধার করা হচ্ছে
আপনি কিভাবে IndexedDB থেকে ডেটা পাবেন তা এখানে:
- একটি লেনদেন শুরু করুন এবং বস্তুর দোকান বা দোকান, এবং ঐচ্ছিকভাবে লেনদেনের প্রকার উল্লেখ করুন।
- সেই লেনদেন থেকে
objectStore()
কল করুন। নিশ্চিত করুন যে আপনি বস্তুর দোকানের নাম উল্লেখ করেছেন। - আপনি যে কীটি পেতে চান তা দিয়ে
get()
কল করুন। ডিফল্টরূপে দোকান একটি সূচক হিসাবে তার কী ব্যবহার করে।
// Using https://github.com/jakearchibald/idb
async function getData() {
const tx = await db.transaction('recipes', 'readonly')
const store = tx.objectStore('recipes');
// Because in our case the `id` is the key, we would
// have to know in advance the value of the id to
// retrieve the record
const value = await store.get([id]);
}
স্টোরেজ ম্যানেজার
আপনার PWA এর সঞ্চয়স্থান কীভাবে পরিচালনা করবেন তা জানা বিশেষভাবে গুরুত্বপূর্ণ নেটওয়ার্ক প্রতিক্রিয়াগুলি সংরক্ষণ এবং স্ট্রিম করার জন্য।
ক্যাশে স্টোরেজ, ইনডেক্সডডিবি, ওয়েব স্টোরেজ, এমনকি পরিষেবা কর্মী ফাইল এবং এর নির্ভরতা সহ সমস্ত স্টোরেজ বিকল্পগুলির মধ্যে স্টোরেজ ক্ষমতা ভাগ করা হয়। যাইহোক, উপলব্ধ স্টোরেজের পরিমাণ ব্রাউজার থেকে ব্রাউজারে পরিবর্তিত হয়। আপনি রান আউট হওয়ার সম্ভাবনা নেই; সাইটগুলি কিছু ব্রাউজারে মেগাবাইট এমনকি গিগাবাইট ডেটা সঞ্চয় করতে পারে। ক্রোম, উদাহরণস্বরূপ, ব্রাউজারটিকে মোট ডিস্কের 80% পর্যন্ত স্থান ব্যবহার করার অনুমতি দেয় এবং একটি পৃথক উৎস সমগ্র ডিস্কের স্থানের 60% পর্যন্ত ব্যবহার করতে পারে। স্টোরেজ API সমর্থন করে এমন ব্রাউজারগুলির জন্য, আপনার অ্যাপ, এর কোটা এবং এর ব্যবহারের জন্য এখনও কতটা সঞ্চয়স্থান রয়েছে তা আপনি জানতে পারবেন। নিম্নলিখিত উদাহরণটি অনুমান কোটা এবং ব্যবহার পেতে স্টোরেজ API ব্যবহার করে, তারপরে ব্যবহৃত শতাংশ এবং অবশিষ্ট বাইট গণনা করে। নোট করুন যে navigator.storage
StorageManager
এর একটি উদাহরণ প্রদান করে। একটি পৃথক Storage
ইন্টারফেস আছে এবং তাদের বিভ্রান্ত করা সহজ।
if (navigator.storage && navigator.storage.estimate) {
const quota = await navigator.storage.estimate();
// quota.usage -> Number of bytes used.
// quota.quota -> Maximum number of bytes available.
const percentageUsed = (quota.usage / quota.quota) * 100;
console.log(`You've used ${percentageUsed}% of the available storage.`);
const remaining = quota.quota - quota.usage;
console.log(`You can write up to ${remaining} more bytes.`);
}
Chromium DevTools-এ, আপনি অ্যাপ্লিকেশান ট্যাবে স্টোরেজ বিভাগটি খুলে আপনার সাইটের কোটা এবং এটি কী ব্যবহার করছে তা ভেঙে কতটা স্টোরেজ ব্যবহার করা হয়েছে তা দেখতে পারেন।
Firefox এবং Safari বর্তমান উৎসের জন্য সমস্ত স্টোরেজ কোটা এবং ব্যবহার দেখার জন্য একটি সারাংশ স্ক্রীন অফার করে না।
ডেটা স্থিরতা
নিষ্ক্রিয়তার পরে বা স্টোরেজ চাপে স্বয়ংক্রিয় ডেটা উচ্ছেদ এড়াতে আপনি সামঞ্জস্যপূর্ণ প্ল্যাটফর্মগুলিতে অবিরাম স্টোরেজের জন্য ব্রাউজারকে জিজ্ঞাসা করতে পারেন। মঞ্জুর করা হলে, ব্রাউজার কখনই স্টোরেজ থেকে ডেটা উচ্ছেদ করবে না। এই সুরক্ষার মধ্যে রয়েছে পরিষেবা কর্মী নিবন্ধন, IndexedDB ডাটাবেস এবং ক্যাশে স্টোরেজে থাকা ফাইল। নোট করুন যে ব্যবহারকারীরা সর্বদা দায়িত্বে থাকেন, এবং ব্রাউজারটি স্থায়ী সঞ্চয়স্থান মঞ্জুর করলেও তারা যেকোন সময় সঞ্চয়স্থান মুছে ফেলতে পারে।
ক্রমাগত স্টোরেজের অনুরোধ করতে, StorageManager.persist()
এ কল করুন। আগের মতো, StorageManager
ইন্টারফেসটি navigator.storage
সম্পত্তির মাধ্যমে অ্যাক্সেস করা হয়।
async function persistData() {
if (navigator.storage && navigator.storage.persist) {
const result = await navigator.storage.persist();
console.log(`Data persisted: ${result}`);
}
এছাড়াও আপনি StorageManager.persisted()
কল করে বর্তমান মূলে স্থায়ী সঞ্চয়স্থান ইতিমধ্যেই মঞ্জুর করা হয়েছে কিনা তা পরীক্ষা করতে পারেন। ফায়ারফক্স ক্রমাগত স্টোরেজ ব্যবহার করার জন্য ব্যবহারকারীর কাছ থেকে অনুমতির অনুরোধ করে। ক্রোমিয়াম-ভিত্তিক ব্রাউজারগুলি ব্যবহারকারীর জন্য বিষয়বস্তুর গুরুত্ব নির্ধারণ করতে হিউরিস্টিকের উপর ভিত্তি করে অধ্যবসায় দেয় বা অস্বীকার করে। Google Chrome-এর জন্য একটি মানদণ্ড হল, উদাহরণস্বরূপ, PWA ইনস্টলেশন। ব্যবহারকারী যদি অপারেটিং সিস্টেমে PWA-এর জন্য একটি আইকন ইনস্টল করে থাকেন, তাহলে ব্রাউজারটি স্থায়ী স্টোরেজ মঞ্জুর করতে পারে।