আপনার ওয়েব অ্যাপ সম্পর্কে বোঝা
ব্যবহারকারীকে দুর্দান্ত অভিজ্ঞতা প্রদান করার জন্য হাই-পারফর্ম্যান্স ওয়েব অ্যাপ্লিকেশন অত্যন্ত গুরুত্বপূর্ণ। ওয়েব অ্যাপ্লিকেশন আরও জটিল হয়ে ওঠার সাথে সাথে, আকর্ষণীয় অভিজ্ঞতা তৈরি করার জন্য পারফর্ম্যান্সের প্রভাব বোঝা অত্যন্ত গুরুত্বপূর্ণ। গত কয়েক বছর ধরে, নেটওয়ার্কের পারফর্ম্যান্স, লোড টাইম ইত্যাদি বিশ্লেষণ করার জন্য ব্রাউজারে বিভিন্ন API দেখা গেছে, তবে আপনার অ্যাপ্লিকেশন কী কারণে স্লো হয়ে যাচ্ছে তা খুঁজে বের করার জন্য এগুলি পর্যাপ্ত নমনীয়তার সাথে সূক্ষ্ম বিবরণ দেয় না। User Timing API লিখুন যা এমন একটি মেকানিজম প্রদান করে যার সাহায্যে আপনার ওয়েব অ্যাপ্লিকেশন কোথায় সময় ব্যয় করছে তা শনাক্ত করতে পারবেন। এই নিবন্ধে আমরা API এবং এটি কীভাবে ব্যবহার করতে হয় তার উদাহরণ কভার করব।
আপনি যা পরিমাপ করতে পারবেন না তা অপ্টিমাইজ করতে পারবেন না
কোনও ধীরগতির ওয়েব অ্যাপ্লিকেশনকে দ্রুত করার প্রথম ধাপ হল, কোথায় সময় ব্যয় হচ্ছে তা খুঁজে বের করা। জাভাস্ক্রিপ্ট কোডের বিভিন্ন অংশের সময়ের উপর প্রভাব পরিমাপ করা হল হট স্পট শনাক্ত করার আদর্শ উপায়, যা পারফর্ম্যান্স কীভাবে উন্নত করা যায় তা খুঁজে বের করার প্রথম ধাপ। তবে, User Timing API-এর মাধ্যমে আপনি জাভাস্ক্রিপ্টের বিভিন্ন অংশে API কল যোগ করতে পারবেন এবং তারপর বিস্তারিত টাইমিং ডেটা এক্সট্র্যাক্ট করতে পারবেন যা আপনাকে অপ্টিমাইজ করতে সাহায্য করবে।
হাই রেজোলিউশন টাইম ও now()
সঠিক সময় পরিমাপের একটি মৌলিক অংশ হল নির্ভুলতা। In the old days we had timing based around millisecond measurement which is OK, but building a jank-free 60 FPS site means each frame needs to be drawn in 16ms. তাই, আপনার কাছে শুধুমাত্র মিলিসেকেন্ডের নির্ভুলতা থাকলে, ভাল বিশ্লেষণের জন্য প্রয়োজনীয় নির্ভুলতার অভাব হয়। হাই রেজোলিউশন টাইম লিখুন, এটি হল নতুন টাইমিং টাইপ যা আধুনিক ব্রাউজারে বিল্ট-ইন থাকে। হাই রেজোলিউশন টাইম আমাদের ফ্লোটিং পয়েন্ট টাইম স্ট্যাম্প দেয় যা মাইক্রোসেকেন্ড রেজোলিউশন পর্যন্ত সঠিক হতে পারে - আগের থেকে হাজার গুণ ভালো।
আপনার ওয়েব অ্যাপ্লিকেশনে বর্তমান সময় জানতে, now() মেথড কল করুন যা পারফর্ম্যান্স ইন্টারফেসের এক্সটেনশন তৈরি করে। নিম্নলিখিত কোড থেকে এটি কীভাবে করতে হয় তা জানতে পারবেন:
var myTime = window.performance.now();
PerformanceTiming নামে আরেকটি ইন্টারফেস আছে যা আপনার ওয়েব অ্যাপ্লিকেশন লোড হওয়ার সাথে সম্পর্কিত বিভিন্ন সময় প্রদান করে। now() পদ্ধতিটি navigationStartPerformanceTiming-এ সময় হওয়ার পর থেকে অতিবাহিত সময় ফিরিয়ে দেয়।
DOMHighResTimeStamp-এর ধরন
অতীতে ওয়েব অ্যাপ্লিকেশনের সময় নির্ধারণ করার চেষ্টা করার সময় আপনি Date.now()-এর মতো কিছু ব্যবহার করতেন যা DOMTimeStamp রিটার্ন করে। DOMTimeStamp তার ভ্যালু হিসেবে মিলিসেকেন্ডের একটি পূর্ণসংখ্যা দেখায়। হাই রেজোলিউশন টাইমের জন্য প্রয়োজনীয় আরও বেশি নির্ভুলতা প্রদান করতে, DOMHighResTimeStamp নামে একটি নতুন ধরন চালু করা হয়েছে। এই ধরনের ভ্যালু হল ফ্লোটিং পয়েন্ট ভ্যালু যা মিলিসেকেন্ডে সময়ও দেখায়। কিন্তু যেহেতু এটি ফ্লোটিং পয়েন্ট, তাই ভ্যালুটি ভগ্নাংশ মিলিসেকেন্ড দেখাতে পারে এবং তাই এক মিলিসেকেন্ডের এক হাজার ভাগের এক ভাগ পর্যন্ত নির্ভুলতা দিতে পারে।
ব্যবহারকারীর সময় ইন্টারফেস
এখন আমাদের কাছে হাই রেজোলিউশন টাইম স্ট্যাম্প আছে, তাই আসুন ব্যবহারকারীর টাইমিং ইন্টারফেস ব্যবহার করে টাইমিং সংক্রান্ত তথ্য বের করি।
ব্যবহারকারীর টাইমিং ইন্টারফেস এমন ফাংশন প্রদান করে যা আমাদের অ্যাপ্লিকেশনের বিভিন্ন জায়গায় পদ্ধতি কল করতে দেয় যা আমাদের সময় কোথায় ব্যয় হচ্ছে তা ট্র্যাক করতে দেওয়ার জন্য একটি হ্যানসেল এবং গ্রেটেল স্টাইলের ব্রেডক্রাম্ব ট্রেইল প্রদান করতে পারে।
mark() ব্যবহৃত হচ্ছে
mark() পদ্ধতি হল আমাদের টাইমিং বিশ্লেষণ টুলকিটের প্রধান টুল। mark() আমাদের জন্য টাইম স্ট্যাম্প স্টোর করে। mark()-এর সবচেয়ে উপযোগী দিক হল, আমরা টাইম স্ট্যাম্পের নাম দিতে পারি এবং API নাম ও টাইম স্ট্যাম্পকে একটি ইউনিট হিসেবে মনে রাখবে।
আপনার অ্যাপ্লিকেশনের বিভিন্ন জায়গায় mark() কল করলে, আপনার ওয়েব অ্যাপ্লিকেশনে সেই 'চিহ্ন' হিট করতে কত সময় লেগেছে তা আপনি বুঝতে পারবেন।
স্পেসিফিকেশনে মার্কের জন্য বেশ কিছু সাজেস্ট করা নাম উল্লেখ করা হয়েছে যা আকর্ষণীয় হতে পারে এবং নাম দেখেই বোঝা যায়, যেমন mark_fully_loaded, mark_fully_visible,mark_above_the_fold ইত্যাদি।
যেমন, নিম্নলিখিত কোড ব্যবহার করে অ্যাপ্লিকেশন সম্পূর্ণ লোড হওয়ার সময় আমরা একটি চিহ্ন সেট করতে পারি:
window.performance.mark('mark_fully_loaded');
আমাদের ওয়েব অ্যাপ্লিকেশন জুড়ে নামযুক্ত চিহ্ন সেট করার মাধ্যমে আমরা অনেক টাইমিং ডেটা সংগ্রহ করতে পারি এবং অ্যাপ্লিকেশনটি কী করছে এবং কখন করছে তা বোঝার জন্য আমাদের সুবিধামতো এটি বিশ্লেষণ করতে পারি।
measure()-এর মাধ্যমে পরিমাপ গণনা করা হচ্ছে
আপনি একাধিক টাইমিং মার্ক সেট করার পরে, সেগুলির মধ্যে অতিবাহিত সময় জানতে চাইবেন। এটি করার জন্য আপনি measure() পদ্ধতি ব্যবহার করেন।
measure() পদ্ধতিটি মার্কের মধ্যে অতিবাহিত সময় গণনা করে এবং আপনার মার্ক এবং PerformanceTiming ইন্টারফেসে সুপরিচিত ইভেন্টের নামের মধ্যে সময়ও পরিমাপ করতে পারে।
যেমন, DOM সম্পূর্ণ হওয়া থেকে শুরু করে আপনার অ্যাপ্লিকেশন স্টেট সম্পূর্ণ লোড হওয়া পর্যন্ত সময় আপনি এই ধরনের কোড ব্যবহার করে হিসেব করতে পারেন:
window.performance.measure('measure_load_from_dom', 'domComplete', 'mark_fully_loaded');
আপনি measure() কল করলে, আপনার সেট করা মার্কের থেকে আলাদাভাবে এটি ফলাফল স্টোর করে, যাতে আপনি পরে সেগুলি ফিরিয়ে আনতে পারেন। আপনার অ্যাপ্লিকেশন রান করার সময়, সময় স্টোর করে রাখার মাধ্যমে, অ্যাপ্লিকেশনটি রেসপন্সিভ থাকে এবং আপনার অ্যাপ্লিকেশন কিছু কাজ শেষ করার পরে আপনি সমস্ত ডেটা ডাম্প করতে পারেন যাতে পরে এটি বিশ্লেষণ করা যায়।
clearMarks()-এর সাথে মার্ক বাতিল করা হচ্ছে
কখনও কখনও আপনার সেট-আপ করা একগুচ্ছ মার্ক থেকে মুক্তি পাওয়াটা উপযোগী হতে পারে। যেমন, আপনি হয়ত আপনার ওয়েব অ্যাপ্লিকেশনে ব্যাচ রান করেন এবং তাই আপনি প্রতিটি রান নতুন করে শুরু করতে চান।
clearMarks() নম্বরে কল করে আপনার সেট-আপ করা যেকোনও চিহ্ন থেকে মুক্তি পাওয়া যথেষ্ট সহজ।
তাই নিচের উদাহরণ কোডটি আপনার আগে থেকে থাকা সব মার্ক মুছে দেবে, যাতে আপনি চাইলে আবার টাইমিং রান সেট-আপ করতে পারেন।
window.performance.clearMarks();
অবশ্যই, এমন কিছু পরিস্থিতি থাকতে পারে যেখানে আপনি হয়ত আপনার সব মার্ক মুছে ফেলতে চাইবেন না। তাই আপনি যদি নির্দিষ্ট কোনও চিহ্ন সরাতে চান, তাহলে যে চিহ্নটি সরাতে চান সেটির নাম পাস করতে পারেন। যেমন, নিচের কোডটি:
window.performance.clearMarks('mark_fully_loaded');
প্রথম উদাহরণে আমরা যে চিহ্ন সেট করেছি তা থেকে মুক্তি পায় এবং আমাদের সেট করা অন্য কোনও চিহ্ন অপরিবর্তিত থাকে।
আপনি হয়ত আপনার করা পরিমাপগুলিও মুছে ফেলতে চান এবং এটি করার জন্য একটি সংশ্লিষ্ট পদ্ধতি রয়েছে যাকে clearMeasures() বলা হয়। এটি ঠিক clearMarks()-এর মতোই কাজ করে, তবে আপনার করা যেকোনও পরিমাপের উপর কাজ করে। যেমন, এই কোড:
window.performance.clearMeasures('measure_load_from_dom');
উপরে measure() উদাহরণে আমরা যে পরিমাপ করেছি তা সরিয়ে দেবে। আপনি যদি সব পরিমাপ সরাতে চান, তাহলে এটি ঠিক clearMarks()-এর মতোই কাজ করে - এতে আপনি আর্গুমেন্ট ছাড়াই শুধু clearMeasures() কল করেন।
টাইমিং ডেটা বের করা হচ্ছে
চিহ্ন সেট করা এবং ব্যবধান পরিমাপ করা ভাল, তবে কোনও এক সময় আপনি কিছু বিশ্লেষণ করার জন্য সেই টাইমিং ডেটা পেতে চান। এটিও খুব সহজ, আপনাকে শুধু PerformanceTimeline ইন্টারফেস ব্যবহার করতে হবে।
যেমন, getEntriesByType() পদ্ধতি আমাদের সব মার্ক টাইম বা সব পরিমাপের টাইম আউট একটি তালিকা হিসেবে পেতে দেয় যাতে আমরা এটি বারবার করতে পারি এবং ডেটা বুঝতে পারি। সবচেয়ে ভালো বিষয় হল, তালিকাটি কালানুক্রমিকভাবে ফেরত আসে, তাই আপনি আপনার ওয়েব অ্যাপ্লিকেশনে যে ক্রমে হিট করা হয়েছে সেই ক্রমে চিহ্নগুলি দেখতে পারবেন।
নিচের কোড:
var items = window.performance.getEntriesByType('mark');
আমাদের ওয়েব অ্যাপ্লিকেশনে হিট করা সব মার্কের তালিকা আমাদের কাছে ফেরত পাঠায়, যখন কোড:
var items = window.performance.getEntriesByType('measure');
আমাদের করা সমস্ত পরিমাপের একটি তালিকা আমাদের ফেরত দেয়।
এছাড়াও, আপনি এন্ট্রিগুলির যে নির্দিষ্ট নাম দিয়েছেন, তা ব্যবহার করে এন্ট্রিগুলির একটি তালিকা ফিরে পেতে পারেন। যেমন, এই কোড:
var items = window.performance.getEntriesByName('mark_fully_loaded');
আমাদের একটি তালিকা ফেরত দেবে যাতে একটি আইটেম থাকবে এবং সেই আইটেমে startTime প্রপার্টিতে ‘mark_fully_loaded’ টাইম স্ট্যাম্প থাকবে।
XHR অনুরোধের সময় নির্ধারণ করা (উদাহরণ)
এখন যেহেতু আমরা User Timing API-এর একটি ভালো ছবি পেয়েছি, তাই আমাদের ওয়েব অ্যাপ্লিকেশনে আমাদের সমস্ত XMLHttpRequests কতক্ষণ সময় নেয় তা বিশ্লেষণ করতে আমরা এটি ব্যবহার করতে পারি।
প্রথমে আমরা আমাদের সব send() অনুরোধ পরিবর্তন করব যাতে একটি ফাংশন কল ইস্যু করা যায় যা মার্ক সেট আপ করে এবং একই সাথে আমাদের সাকসেস কলব্যাক পরিবর্তন করব একটি ফাংশন কলের মাধ্যমে যা অন্য একটি মার্ক সেট করে এবং তারপর অনুরোধটি কতক্ষণ সময় নিয়েছে তার একটি পরিমাপ তৈরি করে।
তাই সাধারণত আমাদের XMLHttpRequest দেখতে এরকম হবে:
var myReq = new XMLHttpRequest();
myReq.open('GET', url, true);
myReq.onload = function(e) {
do_something(e.responseText);
}
myReq.send();
আমাদের উদাহরণে, আমরা অনুরোধের সংখ্যা ট্র্যাক করতে এবং প্রতিটি অনুরোধের জন্য একটি পরিমাপ স্টোর করতে একটি গ্লোবাল কাউন্টার যোগ করব। এটি করার জন্য কোডটি এইরকম দেখতে হয়:
var reqCnt = 0;
var myReq = new XMLHttpRequest();
myReq.open('GET', url, true);
myReq.onload = function(e) {
window.performance.mark('mark_end_xhr');
reqCnt++;
window.performance.measure('measure_xhr_' + reqCnt, 'mark_start_xhr', 'mark_end_xhr');
do_something(e.responseText);
}
window.performance.mark('mark_start_xhr');
myReq.send();
উপরের কোডটি আমাদের পাঠানো প্রতিটি XMLHttpRequest-এর জন্য একটি অনন্য নাম ভ্যালু সহ একটি পরিমাপ তৈরি করে। আমরা ধরে নিচ্ছি যে অনুরোধগুলি ক্রমানুসারে চলে - সমান্তরাল অনুরোধের কোডটি একটু বেশি জটিল হতে হবে যাতে অনুরোধগুলি ক্রমানুসারে না হলেও তা ম্যানেজ করা যায়, আমরা এটি পাঠকের জন্য একটি অনুশীলন হিসাবে ছেড়ে দেব।
ওয়েব অ্যাপ্লিকেশন অনেক অনুরোধ করার পরে, আমরা নিচে দেওয়া কোড ব্যবহার করে কনসোলে সেগুলি ডাম্প করতে পারি:
var items = window.performance.getEntriesByType('measure');
for (var i = 0; i < items.length; ++i) {
var req = items[i];
console.log('XHR ' + req.name + ' took ' + req.duration + 'ms');
}
উপসংহার
আপনার ওয়েব অ্যাপ্লিকেশনের যেকোনও ক্ষেত্রে প্রয়োগ করার জন্য User Timing API আপনাকে অনেক দুর্দান্ত টুল দেয়। আপনার ওয়েব অ্যাপ্লিকেশন জুড়ে API কল স্প্রিঙ্কল করে এবং সময় সংক্রান্ত ডেটা পোস্ট-প্রসেস করে আপনার অ্যাপ্লিকেশনের হট-স্পট সহজেই কমিয়ে আনতে পারবেন। এর ফলে, কোথায় সময় ব্যয় হচ্ছে তার একটি স্পষ্ট ছবি তৈরি হবে। কিন্তু আপনার ব্রাউজারে এই API কাজ না করলে কী হবে? কোনও সমস্যা নেই, আপনি এখানে একটি দুর্দান্ত পলিফিল খুঁজে পেতে পারেন যা API-কে খুব ভালভাবে অনুকরণ করে এবং webpagetest.org-এর সাথেও ভালভাবে কাজ করে। তাহলে আর অপেক্ষা কিসের? আপনার অ্যাপ্লিকেশনে এখনই 'ব্যবহারকারীর টাইমিং API' ব্যবহার করে দেখুন, আপনি বুঝতে পারবেন কীভাবে সেগুলির স্পিড বাড়ানো যায় এবং আপনার ব্যবহারকারীরা তাদের অভিজ্ঞতা আরও ভালো করার জন্য আপনাকে ধন্যবাদ জানাবেন।