ব্যবহারকারীরা ব্রাউজারের অন্য যেকোনো কন্ট্রোলের তুলনায় ব্যাক বাটন অনেক বেশি ব্যবহার করেন। তারা আশা করেন যে পূর্ববর্তী স্ক্রিনটি ঠিক যেখানে তারা রেখেছিলেন সেখানেই তাৎক্ষণিকভাবে দেখা যাবে। আধুনিক ব্রাউজারগুলো ব্যাক/ফরওয়ার্ড ক্যাশ বা bfcache-এর মাধ্যমে সেই প্রত্যাশা পূরণ করে। আপনি যখন কোনো পেজ থেকে অন্য পেজে চলে যান, তখন ব্রাউজার সেই পেজটিকে ধ্বংস করার পরিবর্তে মেমরিতে ফ্রিজ (freeze) করে রাখে। যখন আপনি ফিরে আসেন, এটি একটি স্ন্যাপশট (snapshot) পুনরুদ্ধার করে। ব্রাউজার তখন HTML পার্সিং, JavaScript পুনরায় চালানো এবং লেআউট পুনরায় গণনা করার কাজগুলো এড়িয়ে যায়। এর ফলে পেজটি যেন কখনো পুরোপুরি বন্ধই হয়নি, এমন একটি তাৎক্ষণিক অনুভূতি পাওয়া যায়।

bfcache আসলে কী করে

একটি সাধারণ পেজ লোড হওয়া বেশ ব্যয়বহুল প্রক্রিয়া। ব্রাউজারকে রিসোর্স সংগ্রহ করতে হয়, HTML টোকেনাইজ করতে হয়, DOM তৈরি করতে হয়, স্ক্রিপ্ট চালাতে হয়, স্টাইল সমাধান করতে হয়, লেআউট করতে হয়, পিক্সেল পেইন্ট করতে হয় এবং লেয়ার কম্পোজিট করতে হয়। bfcache পেজটিকে RAM-এ একটি ফ্রিজড অবস্থায় রেখে এই প্রায় সব কাজই এড়িয়ে যায়। এটি কোনো ডিস্ক ক্যাশ (disk cache) নয়। ব্যবহারকারী যখন পরবর্তী পেজটি পড়ছেন, তখন রেন্ডার করা পেজটি—যার মধ্যে JavaScript heap, স্ক্রল পজিশন এবং ফর্ম স্টেট অন্তর্ভুক্ত—মেমরিতে অবস্থান করে। যখন ব্যবহারকারী 'ব্যাক' ক্লিক করেন, ব্রাউজার স্ন্যাপশটটিকে পুনরায় সক্রিয় (thaw) করে এবং একটি pageshow ইভেন্ট ফায়ার করে। পেজটি নেটওয়ার্ক স্পর্শ না করেই বা নতুন করে লেআউট তৈরি না করেই পুনরায় চালু হয়। ধীরগতির ডিভাইস বা দুর্বল সংযোগের ব্যবহারকারীদের জন্য, একটি bfcache রিস্টোর এবং একটি ফ্রেশ লোডের মধ্যে পার্থক্য কয়েকশ মিলিসেকেন্ড বা তার বেশি হতে পারে।

কী কারণে এটি কাজ করে না

একজন ডেভেলপার সম্প্রতি ঠিক কী কারণে bfcache বাধাগ্রস্ত হয় তা জানার জন্য একটি পরিচ্ছন্ন পরীক্ষা চালিয়েছেন। তিনি ছয়টি সাধারণ পেজ তৈরি করেছিলেন, যার প্রতিটি একটি করে সন্দেহভাজন বাধা পরীক্ষা করছিল, তারপর তিনি অন্য পেজে চলে গিয়ে ব্যাক বাটন চেপেছিলেন। ফলাফল ছিল স্পষ্ট।

কোনো অস্বাভাবিক হেডার বা স্ক্রিপ্ট ছাড়া একটি বেসলাইন পেজ সফলভাবে রিস্টোর হয়েছিল। একটি beforeunload লিসেনার থাকা পেজটিও কোনো সমস্যা ছাড়াই রিস্টোর হয়েছিল। আশ্চর্যজনকভাবে, Cache-Control: no-store সহ সার্ভ করা একটি পেজও bfcache-এ প্রবেশ করেছিল, যা পুরনো নির্দেশনার বিপরীত। এমনকি একটি লাইভ ব্লগ আর্টিকেলও, যা ফ্রিজ করার জন্য খুব বেশি ডাইনামিক মনে হতে পারে, সফলভাবে রিস্টোর হয়েছিল।

দুটি পেজ ব্যর্থ হয়েছে। একটি unload ইভেন্ট লিসেনার থাকা পেজ রিস্টোর করা সম্ভব হয়নি। একটি ওপেন WebSocket কানেকশন থাকা পেজও ব্লক হয়ে গিয়েছিল। এই দুটি ব্যর্থতা সেই ফাঁদগুলোর দিকে নির্দেশ করে যা প্রতিদিন বাস্তব প্রোডাকশন সাইটগুলোকে বিপদে ফেলে।

unload ইভেন্টের ফাঁদ

শেষ মুহূর্তের ক্লিনআপের (cleanup) জন্য unload ইভেন্টটি দীর্ঘকাল ধরে একটি প্রধান সংকেত হিসেবে ব্যবহৃত হয়ে আসছে। ডেভেলপাররা অ্যানালিটিক্স বিকন ফ্লাশ করতে, টাইমার বন্ধ করতে বা অস্থায়ী স্টেট মুছে ফেলতে এটি ব্যবহার করেন। সমস্যা হলো, bfcache এই ধারণার ওপর ভিত্তি করে তৈরি যে পেজটি পুনরায় ফিরে আসতে পারে। যদি ব্রাউজার একটি unload লিসেনার দেখতে পায়, তবে এটি ধরে নেয় যে পেজটি সম্পূর্ণ ধ্বংস হওয়ার অপেক্ষায় আছে এবং এটি পেজটিকে ফ্রিজ করতে অস্বীকার করে। সংযুক্ত ফাংশনটি খালি হলেও তাতে কোনো গুরুত্ব নেই। প্রতিটি আধুনিক ব্রাউজারে ক্যাশিং বাতিল করার জন্য কেবল লিসেনারের উপস্থিতিই যথেষ্ট।

এর বিকল্প হলো pagehide। এই ইভেন্টটি তখন ফায়ার হয় যখন পেজটি bfcache-এর জন্য ফ্রিজ করা হচ্ছে এবং যখন এটি সত্যিই ডিসকার্ড করা হচ্ছে। আপনি যদি এই দুটির মধ্যে পার্থক্য করতে চান, তবে পেজটি যখন bfcache-এ যাচ্ছে তখন event.persisted প্রপার্টিটি true হবে। তবে বেশিরভাগ টিয়ারডাউন (teardown) কাজের জন্য pagehide উভয় ক্ষেত্রেই কাজ করে। আপনার ক্লিনআপ লজিকের প্রতিটি অংশ unload থেকে সরিয়ে pagehide-এ নিয়ে আসুন। তারপর থার্ড-পার্টি অ্যানালিটিক্স স্নিপেট বা লেগাসি প্লাগইনে লুকিয়ে থাকা unload লিসেনারসহ সব unload লিসেনার পুরোপুরি সরিয়ে ফেলুন।

সক্রিয় কানেকশন বা সংযোগের ফাঁদ

একটি ওপেন নেটওয়ার্ক বা স্টোরেজ কানেকশন নির্দেশ করে যে আপনার পেজটি এখনও কাজ করছে। নেভিগেশনের মুহূর্তে ব্রাউজার সক্রিয় রিসোর্সগুলোর তালিকা তৈরি করে। যদি এটি একটি ওপেন WebSocket, একটি সক্রিয় WebRTC পিয়ার কানেকশন বা একটি দীর্ঘস্থায়ী IndexedDB কানেকশন খুঁজে পায়, তবে এটি ফ্রিজ করা প্রক্রিয়াটি বাতিল করে এবং পেজটিকে স্বাভাবিকভাবে বন্ধ করে দেয়। যতক্ষণ ডেটা বা বাইট প্রবাহিত হতে পারে, ততক্ষণ স্ন্যাপশটটির ওপর ভরসা করা যায় না।

আপনার উচিত pagehide লিসেনারের ভেতরে এই রিসোর্সগুলো বন্ধ করা। আপনার WebSocket-এর close মেথড কল করুন। WebRTC পিয়ার কানেকশনগুলো বন্ধ করুন। যেকোনো অমীমাংসিত (outstanding) IndexedDB ট্রানজ্যাকশন বাতিল বা কমিট করুন। যদি ব্যবহারকারী ফিরে আসার সময় আপনার অ্যাপের সেই চ্যানেলগুলোর প্রয়োজন হয়, তবে pageshow-এর ভেতরে সেগুলো পুনরায় খুলুন। এই 'close-on-pagehide, restore-on-pageshow' প্যাটার্নটি কার্যকারিতা না হারিয়ে পেজটিকে তাৎক্ষণিক ব্যাক নেভিগেশনের জন্য যোগ্য রাখে।

no-store-এর বিস্ময়

বছরের পর বছর ধরে প্রচলিত ধারণা ছিল যে Cache-Control: no-store bfcache প্রতিরোধ করে। Chrome ২০২৫ সালে সেই আচরণ পরিবর্তন করেছে। এখন no-store সহ সার্ভ করা একটি পেজ bfcache-এ প্রবেশ করতে পারে। ব্রাউজার কেবল তখনই ফ্রিজ করা স্ন্যাপশটটি সরিয়ে দেয় যদি অথেন্টিকেশন স্টেট বা কুকি এমনভাবে পরিবর্তিত হয় যা সংরক্ষিত স্টেটকে অবৈধ করে তোলে। আপনি যদি no-store ব্যবহার করে থাকেন as