একটি HTML পেজের লাইফসাইকেলে তিনটি গুরুত্বপূর্ণ ইভেন্ট আছে:
DOMContentLoaded
-- সকল HTML কন্টেন্ট লোড হয়ে DOM ট্রি বিল্ট হলে এটি ট্রিগার হয়, তবে এক্সটার্নাল রিসোর্স যেমন<img>
ট্যাগ এর সোর্স বা<iframe>
সোর্স লোড হওয়ার আগেই এই ইভেন্টটি ট্রিগার হয়।load
-- HTML কন্টেন্ট লোড এবং সকল এক্সটার্নাল রিসোর্স লোড হওয়ার পর এই ইভেন্টটি ট্রিগার হয়।beforeunload/unload
-- ইউজার পেজ লিভ করার পূর্বে।
নিম্নোক্ত কাজে ইভেন্টসমূহ কাজে আসতে পারে:
DOMContentLoaded
event -- DOM রেডি, সুতরাং আমরা হ্যান্ডেলারের মাধ্যমে DOM নোডকে পরিবর্তন করতে পারি।load
event -- এক্সটার্নাল রিসোর্স লোড হওয়ার কারণে স্ট্যাইল বা ইমেজ সাইজ প্রভৃতি নিয়ে কাজ করতে পারি।beforeunload
event -- ইউজার পেজ হতে লিভ হওয়ার পূর্বে কল হয়: সুতরাং আমরা পেজ হতে লিভ হওয়ার পূর্বে ইউজার হতে ডাটা সংরক্ষণ বা অন্যান্য ব্যাপারে নিশ্চায়ন করতে পারি।unload
-- ইউজার প্রায় পেজ হতে লিভ হয়ে গেছে, তবে ইউজারের বিভিন্ন পরিসংখ্যান সংরক্ষনের জন্য আমরা এটি ব্যবহার করতে পারি।
চলুন ইভেন্ট সমূহ সম্পর্কে আরো বিস্তারিত জানি।
document
নোডে DOMContentLoaded
ইভেন্টটি সংগঠিত হয়।
এবং অবশ্যই addEventListener
এর মাধ্যমে হ্যান্ডালার অ্যাসাইন করতে হবে:
document.addEventListener("DOMContentLoaded", ready);
// not "document.onDOMContentLoaded = ..."
যেমন:
<script>
function ready() {
alert('DOM is ready');
// যেহেতু এক্সটার্নাল রিসোর্স লোড হওয়ার পূর্বে এটি ট্রিগার হয় সাইজ দেখাবে 0x0
alert(`Image size: ${img.offsetWidth}x${img.offsetHeight}`);
}
*!*
document.addEventListener("DOMContentLoaded", ready);
*/!*
</script>
<img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0">
উপরের উদাহরণে DOMContentLoaded
হ্যান্ডালার এক্সিকিউট হবে DOM ট্রি বিল্ড হওয়ার পর, সুতরাং আমরা সকল এলিমেন্ট অ্যাক্সেস করতে পারব, এমনকি <img>
ও।
কিন্তু এটির সোর্স ডাওনলোড না হওয়ায় সাইজ শূন্য দেখাবে।
প্রথম দেখাতে DOMContentLoaded
ইভেন্টকে সাধারন মনে হয়। DOM ট্রি রেডি হলেই ইভেন্ট ট্রিগার হবে। তবে এর কিছু ভিন্নতা আছে।
যখন ব্রাউজার HTML-document কে প্রসেস করে তখন যদি <script>
ট্যাগ এক্সিকিউট হয় তখন এদেরকে DOM ট্রি বিল্ডের পূর্বে এরা <script>
কে এক্সিকিউট করে। একারণে <script>
সমূহ এক্সিকিউট না হওয়া পর্যন্ত DOMContentLoaded
ট্রিগার হবে না।
সুতরাং হ্যান্ডেলার অবশ্যই সবার শেষে এক্সিকিউট হবে:
<script>
document.addEventListener("DOMContentLoaded", () => {
alert("DOM ready!");
});
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js"></script>
<script>
alert("Library loaded, inline script executed");
</script>
উপরের উদাহরণে আমরা দেখেছি, প্রথমে "Library loaded..." দেখাবে, তারপর "DOM ready!"
তবে এক্ষেত্রে দুটি ভিন্নতা আছে:
1. `async` অ্যাট্রিবিউট সহ স্ক্রিপ্টস সমূহ `DOMContentLoaded` কে ব্লক করবে না, বিস্তারিত পরবর্তী অধ্যায়ে (info:script-async-defer)।
2. ডায়নামিক্যালি জেনারেট স্ক্রিপ্টস সমূহ যেমন: `document.createElement('script')` এর মাধ্যমে সংযুক্ত স্ক্রিপ্টস সমূহ ইভেন্টকে ব্লক করে না।
এক্সটার্নাল স্ট্যাইলশীট DOM এ কোন প্রভাব ফেলে না, সুতরাং DOMContentLoaded
এদের জন্য অপেক্ষা করবে না।
তবে একটি ব্যাপার জেনে রাখা উচিত। যদি স্ট্যাইল শীটের পরে স্ক্রিপ্ট থাকে, তাহলে স্ক্রিপ্টটি স্ট্যাইল শীট লোড হওয়া পর্যন্ত অপেক্ষা করবে:
<link type="text/css" rel="stylesheet" href="style.css">
<script>
// the script doesn't not execute until the stylesheet is loaded
alert(getComputedStyle(document.body).marginTop);
</script>
উপরে বর্ণিত উদাহরণের মত অনেক সময় আমাদের এলিমেন্টের বিভিন্ন স্ট্যাইল প্রপার্টি সম্পর্কে জানা লাগে তখন আমরা স্ট্যাইলশীট প্রথমে লোড করি। সুতরাং এটি স্ট্যাইল লোড হওয়ার জন্য অপেক্ষা করবে।
সুতরাং DOMContentLoaded
যেভাবে স্ক্রিপ্টস এর জন্য অপেক্ষা করে তেমনি স্ট্যাইলশীটের জন্যও করে।
DOMContentLoaded
এর মাধ্যমে ফায়ারফক্স, ক্রোম এবং অপেরাতে স্বয়ংক্রিয়ভাবে ফর্ম ভ্যালু autofill সাপোর্ট করে।
উদাহরণস্বরূপ, যদি কোন লগিন পেজে লগিন এবং পাসওয়ার্ড ফর্ম থাকে, এবং আপনি যদি remember me জাতীয় কোন ভ্যালু সেভ করে রাখেন তাহলে ব্রাউজার মানগুলো মনে রাখে এবং DOMContentLoaded
ইভেন্টের মাধ্যমে ইনপুট ফিল্ডগুলো স্বয়ংক্রিয়ভাবে ফিল আপ করে।
সুতরাং যদি কোন বড় স্ক্রিপ্টস এর জন্য যদি DOMContentLoaded
ইভেন্ট ট্রিগার হতে দেরি হয়, তাহলে autofill হতে দেরি হবে। আপনি হয়তো অনেক সাইট দেখেছেন, যেখানে ব্রাউজার অটোফিল সাপোর্ট করার পরও লগিন ফিল্ড গুলো ফুল পেজ লোড না হওয়া পর্যন্ত ফিল আপ হয় না। এটি ঘটে DOMContentLoaded
ইভেন্ট এর কারণে, কেননা ফুল পেজ লোড না হওয়া পর্যন্ত DOMContentLoaded
ইভেন্ট ট্রিগার হয় না।
ওয়েব পেজের সকল ধরণের রিসোর্স যেমন ইমেজ, স্ট্যাইল ইত্যাদি লোড হওয়ার পর window
অবজেক্টের load
ইভেন্ট ট্রিগার হয়। এবং এটিকে আমরা onload
প্রপার্টির মাধ্যমে অ্যাক্সেস করতে পারি।
নিচের উদাহরণে ইমেজের সাইজ, স্ট্যাইল ইত্যাদি সঠিকভাবে দেখাবে, কেননা window.onload
সকল রিসোর্স লোড হওয়া পর্যন্ত অপেক্ষা করে:
<script>
window.onload = function() { // window.addEventListener('load', (event) => { এভাবেও ডিফাইন করতে পারি
alert('Page loaded');
// image is loaded at this time
alert(`Image size: ${img.offsetWidth}x${img.offsetHeight}`);
};
</script>
<img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0">
ইউজার পেজ হতে লিভ হওয়ার পূর্বে window
এর unload
ইভেন্টটি ট্রিগার হয়। তবে এক্ষেত্রে আমরা কনফার্মেশন বা পপ আপ দেখাতে পারব না।
তবে আমরা চাইলে ইউজারের ব্যবহৃত পরিসংখ্যান সংরক্ষন করতে পারি।
আমরা বিভিন্ন ভাবে ডাটা সংগ্রহ করতে পারি যেমন মাউস ক্লিক, স্ক্রল ইত্যাদি।
সাধারণত ইউজার যখন পেজ হতে লিভ নেয়, তখন আমরা ডাটা সংরক্ষন করতে চায় এবং unload
ইভেন্টটি ট্রিগার করি।
এজন্য একটি বিশেষ মেথড আছে navigator.sendBeacon(url, data)
, বিস্তারিত https://w3c.github.io/beacon/।
এটি ব্যাকগ্রাউন্ডে ডাটা সেন্ড করে। পেজ হতে লিভ হওয়ার পরও sendBeacon
কাজ করে।
উদাহরণস্বরূপ:
let analyticsData = { /* object with gathered data */ };
window.addEventListener("unload", function() {
navigator.sendBeacon("/analytics", JSON.stringify(analyticsData));
};
- রিকুয়েস্ট মেথডটি হল POST।
- আমরা স্ট্রিং ছাড়াও অন্যান্য ফরম্যাটে ডাটা পাঠাতে পারি, বিস্তারিত এখানে info:fetch, ্তবে সাধারণত এটি stringify অবজেক্ট হয়।
- ডাটা সাইজ সর্বোচ্চ 64kb।
sendBeacon
রিকুয়েস্ট যখন সমাপ্ত হয়, ততক্ষণে আমরা পেজটি থেকে লিভ নিয়ে নেই, সুতরাং সার্ভার হতে কোন রেস্পেন্স পাব না।
এছাড়াও জেনেরিক নেটওয়ার্ক রিকুয়েস্ট সমূহের fetch এর keepalive
নামের একটি ফ্ল্যাগ আছে । আরো বিস্তারিত জানতে পারব এই অধ্যায়ে info:fetch-api।
যদি আমরা পেজ লিভ করার আগে ইউজারকে কোন কনফার্মেশন দেখাতে চাই, তাহলে unload
এর সাহায্যে পারব না, তবে আরেকটি ইভেন্ট আছে -- onbeforeunload
।
যদি ভিজিটর এক পেজ হতে অন্য পেজে নেভিগেশন করে অথবা পেজ হতে লিভ নিতে চায় তখন beforeunload
ইভেন্ট ট্রিগার হয়।
এটির সাহায্যে ইউজারকে কনফার্মেশন মেসেজ দেখাতে পারি।
নিচের কোডটি রান করে ব্রাউজার রিলোড করার ট্রাই করুন:
window.onbeforeunload = function() {
return false;
};
কোন non-empty স্ট্রিং রিটার্নের মাধ্যমেও আমরা ইভেন্ট ক্যান্সেল করতে পারি। পূর্বে এটি কাস্টম মেসেজ দেখাতে ব্যবহার হত তবে মডার্ন ব্রাউজার কাস্টম কনফার্মেশন মেসেজ সাপোর্ট করে না modern specification।
উদাহরণস্বরূপ:
window.onbeforeunload = function() {
return "There are unsaved changes. Leave now?";
};
এই ইভেন্টটির মাধ্যমে অনেক ডেভলাপার ইউজার কে বিভিন্ন রকমের মেসেজ দেখিয়ে বিভ্রান্তি করার কারণে এটি পরিবর্তন করা হয়েছে। তবে ব্রাউজারগুলোর পুরনো ভার্সনগুলোতে এটি কাজ করতে পারে, তবে মেসেজটি কাস্টমাইজ করার কোন উপায় নেই।
যদি আমরা ডকুমেন্ট লোড হওয়ার পর DOMContentLoaded
হ্যান্ডালার সেট করি তাহলে কি ঘটবে?
সাধারণত, এটি এক্সিকিউট হবে না।
অনেক সময় ডকুমেন্ট কি লোড হয়ে গেছে নাকি লোডিং ধাপে আছে তার উপর নির্ভর করে আমাদের কোন কার্য সম্পাদন করা লাগে, এটি আমরা কিভাবে করতে পারি?
সৌভাগ্যক্রমে document
অবজেক্টের একটি প্রপার্টি আছে document.readyState
নামের যা আমাদের পেজ লোডিং এর ধাপসমূহ রিটার্ন করে।
এর ৩টি ভ্যালু আছে:
"loading"
-- ডকুমেন্ট লোডিং।"interactive"
-- সম্পূর্ন ডকুমেন্টটি পার্স করে পড়া হয়েছে।"complete"
-- সম্পূর্ন ডকুমেন্টটি পার্স করে পড়া হয়েছে এবং সকল ধরণের রিসোর্স যেমন (img) ও লোড হয়েছে।
সুতরাং আমরা document.readyState
এর উপর ভিত্তি করে হ্যান্ডেলার সেট করতে পারি।
উদাহরণস্বরূপ:
function work() { /*...*/ }
if (document.readyState == 'loading') {
// still loading, wait for the event
document.addEventListener('DOMContentLoaded', work);
} else {
// DOM is ready!
work();
}
এছাড়াও readystatechange
নামের একটি ইভেন্ট আছে যেটি readyState
এর ভ্যালু পরিবর্তনের সাথে সাথে ট্রিগার হয়:
// current state
console.log(document.readyState);
// print state changes
document.addEventListener('readystatechange', () => console.log(document.readyState));
অনেক আগে থেকে readystatechange
ইভেন্টটি ডকুমেন্ট এর স্টেট ট্রাকিংয়ের জন্য ব্যবহার করা হচ্ছিল, তবে বর্তমানে এর তেমন ব্যবহার নেই।
চলুন সম্পূর্ণ লাইফসাইকেল টা দেখি।
এখানে <iframe>
, <img>
আছে ইভেন্ট লগের জন্য একটি log()
ফাংশন আছে:
<script>
log('initial readyState:' + document.readyState);
document.addEventListener('readystatechange', () => log('readyState:' + document.readyState));
document.addEventListener('DOMContentLoaded', () => log('DOMContentLoaded'));
window.onload = () => log('window onload');
</script>
<iframe src="iframe.html" onload="log('iframe onload')"></iframe>
<img src="http://en.js.cx/clipart/train.gif" id="img">
<script>
img.onload = () => log('img onload');
</script>
উদাহরণটি এখানে দেখুন in the sandbox
এটির আউটপুট হবে অনেকটা এমন:
- [1] initial readyState:loading
- [2] readyState:interactive
- [2] DOMContentLoaded
- [3] iframe onload
- [4] img onload
- [4] readyState:complete
- [4] window onload
তৃতীয় বন্ধনীর সংখ্যাটি বুঝায় ইভেন্ট সমূহ ট্রিগার আনুমানিক কত সময় লেগেছে।
- এখানে দেখছি
DOMContentLoaded
এর আগেdocument.readyState
এর মানinteractive
দেখাচ্ছে। এখানে দুটিই একই সময়ে ঘটে তাই সময় একই দেখাচ্ছে। - সকল রিসোর্স (
iframe
andimg
) লোড হওয়ার পরdocument.readyState
এর মানcomplete
হবে। যার কারণে ৫,৬,৭ নং ধাপের সময় একই দেখাচ্ছে।document.readyState
এর মানcomplete
এবংwindow onload
উভয়ই একই স্টেট নির্দেশ করে।
পেজ লোড ইভেন্ট সমূহ:
- পেজ লোডিংয়ের সময় DOM রেডি হলে
document
এরDOMContentLoaded
ইভেন্টটি ট্রিগার হয়। এই ধাপে আমরা যেকোন এলিমেন্ট নোড কে অ্যাক্সেস করতে পারি। <script>...</script>
বা<script src="..."></script>
স্ক্রিপ্টস সমূহ DOMContentLoaded কে ব্লক করে রাখে, স্ক্রিপ্টস সমূহ এক্সিকিউট হওয়ার পর DOMContentLoaded ট্রিগার হয়।- ইমেজ বা অন্যান্য এক্সটার্নাল রিসোর্স যেমন
iframe
লোড হতে থাকে। - সকল ধরণের রিসোর্স লোড হওয়ার পর
window
এরload
ইভেন্টটি ট্রিগার হয়। তবে এটি খুব কমই ব্যবহার করা হয় কেননা বেশিরভাগ সময় আমাদের এলিমেন্টে বিভিন্ন ধরণের অপারেশন চালানো লাগে DOM ট্রি রেডি হওয়ার পরপরই। - ইউজার যখন ব্রাউজার হতে লিভ করতে চাই তখন
window
অবজেক্টেরbeforeunload
ইভেন্টটি ট্রিগার হয়, এবং যদি ইভেন্টটি ক্যান্সেল করা হয় তখন এটি ইউজারকে একটি কনফার্মেশন মেসেজ দেখায়(যেমন we have unsaved changes). - এবং ইউজার যখন পেজ হতে লিভ করবে তখন
window
অবজেক্টেরunload
ইভেন্টটি ট্রিগার হবে, এবং এটির সাহায্যে কোন ধরণের পপ আপ বা অন্য কোন মেসেজ দেখাতে পারব না, তবে অ্যানালাইসিসের জন্য ইউজারের ডাটাnavigator.sendBeacon
এর মাধ্যমে সংরক্ষন করতে পারি। document.readyState
ডকুমেন্টের কারেন্ট স্টেট রিটার্ন করে,readystatechange
ইভেন্টের মাধ্যমে আমরা স্টেট ট্র্যাক করতে পারি:loading
-- ডকুমেন্ট স্টেট লোডিং।interactive
-- সম্পূর্ন ডকুমেন্টটি পার্স করে পড়া হয়েছে, এবং সাথে সাথেDOMContentLoaded
ইভেন্টটি ট্রিগার হবে, তবেinteractive
প্রথমে ট্রিগার হয়।complete
-- সম্পূর্ন ডকুমেন্টটি পার্স করে পড়া হয়েছে এবং সকল ধরণের রিসোর্স যেমন (img) ও লোড হয়েছে, এবং সাথে সাথেwindow.onload
ইভেন্টটি ট্রিগার হবে।