ভূমিকা
স্পিনিং রিফ্রেশ, চপি পেজ ট্রানজিশন এবং ট্যাপ ইভেন্টে পর্যায়ক্রমিক বিলম্ব আজকের মোবাইল ওয়েব পরিবেশে মাথাব্যথার কয়েকটি মাত্র। বিকাশকারীরা যতটা সম্ভব স্থানীয়দের কাছাকাছি যাওয়ার চেষ্টা করছে, কিন্তু প্রায়ই হ্যাক, রিসেট এবং কঠোর কাঠামোর দ্বারা লাইনচ্যুত হয়।
এই নিবন্ধে, আমরা একটি মোবাইল HTML5 ওয়েব অ্যাপ তৈরি করতে ন্যূনতম যা লাগে তা নিয়ে আলোচনা করব। মূল বিষয় হল লুকানো জটিলতাগুলিকে প্রকাশ করা যা আজকের মোবাইল ফ্রেমওয়ার্কগুলি লুকানোর চেষ্টা করে৷ আপনি একটি সংক্ষিপ্ত পদ্ধতি (কোর HTML5 API ব্যবহার করে) এবং মৌলিক মৌলিক বিষয়গুলি দেখতে পাবেন যা আপনাকে আপনার নিজস্ব কাঠামো লিখতে বা আপনি বর্তমানে যেটি ব্যবহার করছেন তাতে অবদান রাখতে সক্ষম করবে৷
হার্ডওয়্যার ত্বরণ
সাধারণত, GPU গুলি বিস্তারিত 3D মডেলিং বা CAD ডায়াগ্রাম পরিচালনা করে, কিন্তু এই ক্ষেত্রে, আমরা চাই আমাদের আদিম অঙ্কনগুলি (divs, ব্যাকগ্রাউন্ড, ড্রপ শ্যাডো সহ পাঠ্য, চিত্র ইত্যাদি) GPU-এর মাধ্যমে মসৃণভাবে উপস্থিত হোক এবং মসৃণভাবে অ্যানিমেট হোক। দুর্ভাগ্যের বিষয় হল যে বেশিরভাগ ফ্রন্ট-এন্ড ডেভেলপাররা শব্দার্থবিদ্যা সম্পর্কে উদ্বিগ্ন না হয়ে এই অ্যানিমেশন প্রক্রিয়াটিকে তৃতীয়-পক্ষের ফ্রেমওয়ার্কের সাথে ডিশ করছে, কিন্তু এই মূল CSS3 বৈশিষ্ট্যগুলি কি মুখোশযুক্ত হওয়া উচিত? এই জিনিসটির যত্ন নেওয়া কেন গুরুত্বপূর্ণ তা আমি আপনাকে কয়েকটি কারণ দিই:
মেমরি বরাদ্দ এবং কম্পিউটেশনাল বোঝা — আপনি যদি শুধু হার্ডওয়্যার ত্বরণের জন্য DOM-এর প্রতিটি উপাদান সংমিশ্রণে যান, আপনার কোডে কাজ করা পরবর্তী ব্যক্তি আপনাকে তাড়া করতে পারে এবং আপনাকে মারাত্মকভাবে মারতে পারে।
শক্তি খরচ - স্পষ্টতই, যখন হার্ডওয়্যার কিক হয়, ব্যাটারিও তাই করে। মোবাইলের জন্য বিকাশ করার সময়, বিকাশকারীরা মোবাইল ওয়েব অ্যাপগুলি লেখার সময় ডিভাইসের সীমাবদ্ধতার বিস্তৃত অ্যারেকে বিবেচনায় নিতে বাধ্য হয়। ব্রাউজার নির্মাতারা আরও বেশি ডিভাইস হার্ডওয়্যারে অ্যাক্সেস সক্ষম করতে শুরু করার কারণে এটি আরও বেশি প্রচলিত হবে।
দ্বন্দ্ব — ইতিমধ্যেই ত্বরান্বিত করা পৃষ্ঠার অংশগুলিতে হার্ডওয়্যার ত্বরণ প্রয়োগ করার সময় আমি জটিল আচরণের সম্মুখীন হয়েছি। তাই আপনার ওভারল্যাপিং ত্বরণ আছে কিনা তা জানা খুবই গুরুত্বপূর্ণ।
ব্যবহারকারীর মিথস্ক্রিয়াকে মসৃণ এবং যতটা সম্ভব নেটিভের কাছাকাছি করতে, আমাদের অবশ্যই ব্রাউজারটিকে আমাদের জন্য কাজ করতে হবে। আদর্শভাবে, আমরা চাই মোবাইল ডিভাইসের CPU প্রাথমিক অ্যানিমেশন সেট আপ করুক, তারপর GPU-কে অ্যানিমেশন প্রক্রিয়া চলাকালীন শুধুমাত্র বিভিন্ন স্তর সংমিশ্রণের জন্য দায়ী করুন। এটিই translate3d, স্কেল3d এবং translateZ করে — তারা অ্যানিমেটেড উপাদানগুলিকে তাদের নিজস্ব স্তর দেয়, এইভাবে ডিভাইসটিকে সবকিছু একসাথে মসৃণভাবে রেন্ডার করার অনুমতি দেয়। অ্যাক্সিলারেটেড কম্পোজিটিং এবং ওয়েবকিট কীভাবে কাজ করে সে সম্পর্কে আরও জানতে, আরিয়া হিদায়াতের ব্লগে অনেক ভালো তথ্য রয়েছে।
পৃষ্ঠার রূপান্তর
চলুন একটি মোবাইল ওয়েব অ্যাপ ডেভেলপ করার সময় সবচেয়ে সাধারণ ব্যবহারকারী-মিথস্ক্রিয়া পদ্ধতির তিনটির দিকে নজর দেওয়া যাক: স্লাইড, ফ্লিপ এবং ঘূর্ণন প্রভাব৷
আপনি এখানে এই কোডটি কার্যকরভাবে দেখতে পারেন http://slidfast.appspot.com/slide-flip-rotate.html (দ্রষ্টব্য: এই ডেমোটি একটি মোবাইল ডিভাইসের জন্য তৈরি করা হয়েছে, তাই একটি এমুলেটর চালু করুন, আপনার ফোন বা ট্যাবলেট ব্যবহার করুন, অথবা আপনার ব্রাউজার উইন্ডোর আকার ~1024px বা তার কম কমিয়ে দিন)।
প্রথমে, আমরা স্লাইড, ফ্লিপ, এবং ঘূর্ণন রূপান্তরগুলি বিচ্ছিন্ন করব এবং কীভাবে সেগুলি ত্বরান্বিত হয়। লক্ষ্য করুন কিভাবে প্রতিটি অ্যানিমেশন সিএসএস এবং জাভাস্ক্রিপ্টের তিন বা চার লাইন নেয়।
স্লাইডিং
তিনটি রূপান্তর পদ্ধতির মধ্যে সবচেয়ে সাধারণ, স্লাইডিং পেজ ট্রানজিশন মোবাইল অ্যাপ্লিকেশনের নেটিভ অনুভূতির অনুকরণ করে। ভিউ পোর্টে একটি নতুন বিষয়বস্তু এলাকা আনতে স্লাইড ট্রানজিশন আহ্বান করা হয়েছে।
স্লাইড প্রভাবের জন্য, প্রথমে আমরা আমাদের মার্কআপ ঘোষণা করি:
<div id="home-page" class="page">
<h1>Home Page</h1>
</div>
<div id="products-page" class="page stage-right">
<h1>Products Page</h1>
</div>
<div id="about-page" class="page stage-left">
<h1>About Page</h1>
</div>
পৃষ্ঠাগুলিকে বাম বা ডানে মঞ্চায়ন করার এই ধারণাটি কীভাবে আছে তা লক্ষ্য করুন। এটি মূলত কোন দিক হতে পারে, কিন্তু এটি সবচেয়ে সাধারণ।
আমাদের কাছে এখন মাত্র কয়েকটি লাইনের CSS সহ অ্যানিমেশন প্লাস হার্ডওয়্যার ত্বরণ রয়েছে। প্রকৃত অ্যানিমেশন ঘটে যখন আমরা পৃষ্ঠা ডিভ উপাদানগুলিতে ক্লাস অদলবদল করি।
.page {
position: absolute;
width: 100%;
height: 100%;
/*activate the GPU for compositing each page */
-webkit-transform: translate3d(0, 0, 0);
}
translate3d(0,0,0)
"সিলভার বুলেট" পদ্ধতি হিসাবে পরিচিত।
যখন ব্যবহারকারী একটি নেভিগেশন উপাদান ক্লিক করে, আমরা ক্লাসগুলি অদলবদল করতে নিম্নলিখিত জাভাস্ক্রিপ্টটি চালাই। কোন তৃতীয় পক্ষের ফ্রেমওয়ার্ক ব্যবহার করা হচ্ছে না, এটি সরাসরি জাভাস্ক্রিপ্ট! ;)
function getElement(id) {
return document.getElementById(id);
}
function slideTo(id) {
//1.) the page we are bringing into focus dictates how
// the current page will exit. So let's see what classes
// our incoming page is using. We know it will have stage[right|left|etc...]
var classes = getElement(id).className.split(' ');
//2.) decide if the incoming page is assigned to right or left
// (-1 if no match)
var stageType = classes.indexOf('stage-left');
//3.) on initial page load focusPage is null, so we need
// to set the default page which we're currently seeing.
if (FOCUS_PAGE == null) {
// use home page
FOCUS_PAGE = getElement('home-page');
}
//4.) decide how this focused page should exit.
if (stageType > 0) {
FOCUS_PAGE.className = 'page transition stage-right';
} else {
FOCUS_PAGE.className = 'page transition stage-left';
}
//5. refresh/set the global variable
FOCUS_PAGE = getElement(id);
//6. Bring in the new page.
FOCUS_PAGE.className = 'page transition stage-center';
}
stage-left
বা stage-right
stage-center
হয়ে যায় এবং পৃষ্ঠাটিকে কেন্দ্রের ভিউ পোর্টে স্লাইড করতে বাধ্য করে। ভারী উত্তোলন করতে আমরা সম্পূর্ণভাবে CSS3 এর উপর নির্ভরশীল।
.stage-left {
left: -480px;
}
.stage-right {
left: 480px;
}
.stage-center {
top: 0;
left: 0;
}
এর পরে, চলুন দেখে নেওয়া যাক CSS যা মোবাইল ডিভাইস সনাক্তকরণ এবং ওরিয়েন্টেশন পরিচালনা করে। আমরা প্রতিটি ডিভাইস এবং প্রতিটি রেজোলিউশনকে সম্বোধন করতে পারি ( মিডিয়া কোয়েরি রেজোলিউশন দেখুন)। মোবাইল ডিভাইসে বেশিরভাগ পোর্ট্রেট এবং ল্যান্ডস্কেপ ভিউ কভার করতে আমি এই ডেমোতে কয়েকটি সহজ উদাহরণ ব্যবহার করেছি। এটি প্রতি ডিভাইসে হার্ডওয়্যার ত্বরণ প্রয়োগের জন্যও কার্যকর। উদাহরণস্বরূপ, যেহেতু ওয়েবকিটের ডেস্কটপ সংস্করণটি সমস্ত রূপান্তরিত উপাদানকে ত্বরান্বিত করে (সেটি 2-ডি বা 3-ডি যাই হোক না কেন), এটি একটি মিডিয়া ক্যোয়ারী তৈরি করা এবং সেই স্তরে ত্বরণ বাদ দেওয়া বোধগম্য। মনে রাখবেন যে হার্ডওয়্যার ত্বরণ কৌশলগুলি Android Froyo 2.2+ এর অধীনে কোনো গতির উন্নতি প্রদান করে না। সমস্ত রচনা সফ্টওয়্যার মধ্যে সম্পন্ন করা হয়.
/* iOS/android phone landscape screen width*/
@media screen and (max-device-width: 480px) and (orientation:landscape) {
.stage-left {
left: -480px;
}
.stage-right {
left: 480px;
}
.page {
width: 480px;
}
}
ফ্লিপিং
মোবাইল ডিভাইসে, ফ্লিপিং আসলে পৃষ্ঠাটি সোয়াইপ করা হিসাবে পরিচিত। এখানে আমরা iOS এবং Android (WebKit-ভিত্তিক) ডিভাইসে এই ইভেন্টটি পরিচালনা করতে কিছু সাধারণ জাভাস্ক্রিপ্ট ব্যবহার করি।
এটিকে অ্যাকশনে দেখুন http://slidfast.appspot.com/slide-flip-rotate.html ।
টাচ ইভেন্ট এবং ট্রানজিশনের সাথে ডিল করার সময়, আপনি প্রথমে যে জিনিসটি চাইবেন তা হল উপাদানটির বর্তমান অবস্থানের উপর একটি হ্যান্ডেল পাওয়া। WebKitCSSMatrix-এ আরও তথ্যের জন্য এই ডকটি দেখুন।
function pageMove(event) {
// get position after transform
var curTransform = new WebKitCSSMatrix(window.getComputedStyle(page).webkitTransform);
var pagePosition = curTransform.m41;
}
যেহেতু আমরা পেজ ফ্লিপের জন্য একটি CSS3 ইজি-আউট ট্রানজিশন ব্যবহার করছি, তাই স্বাভাবিক element.offsetLeft
কাজ করবে না।
এরপরে আমরা ব্যবহারকারী কোন দিকে ফ্লিপ করছে তা বের করতে চাই এবং একটি ইভেন্ট (পৃষ্ঠা নেভিগেশন) সংঘটিত হওয়ার জন্য একটি থ্রেশহোল্ড সেট করতে চাই।
if (pagePosition >= 0) {
//moving current page to the right
//so means we're flipping backwards
if ((pagePosition > pageFlipThreshold) || (swipeTime < swipeThreshold)) {
//user wants to go backward
slideDirection = 'right';
} else {
slideDirection = null;
}
} else {
//current page is sliding to the left
if ((swipeTime < swipeThreshold) || (pagePosition < pageFlipThreshold)) {
//user wants to go forward
slideDirection = 'left';
} else {
slideDirection = null;
}
}
আপনি আরও লক্ষ্য করবেন যে আমরা swipeTime
মিলিসেকেন্ডেও পরিমাপ করছি। এটি নেভিগেশন ইভেন্টটিকে ফায়ার করার অনুমতি দেয় যদি ব্যবহারকারী দ্রুত একটি পৃষ্ঠা চালু করতে স্ক্রীন সোয়াইপ করেন।
পৃষ্ঠার অবস্থান এবং অ্যানিমেশনগুলিকে নেটিভ দেখাতে যখন একটি আঙুল স্ক্রীন স্পর্শ করে, আমরা প্রতিটি ইভেন্ট ফায়ারিংয়ের পরে CSS3 রূপান্তর ব্যবহার করি।
function positionPage(end) {
page.style.webkitTransform = 'translate3d('+ currentPos + 'px, 0, 0)';
if (end) {
page.style.WebkitTransition = 'all .4s ease-out';
//page.style.WebkitTransition = 'all .4s cubic-bezier(0,.58,.58,1)'
} else {
page.style.WebkitTransition = 'all .2s ease-out';
}
page.style.WebkitUserSelect = 'none';
}
ট্রানজিশনে সেরা নেটিভ অনুভূতি দেওয়ার জন্য আমি কিউবিক-বেজিয়ারের সাথে খেলার চেষ্টা করেছি, কিন্তু সহজ-আউট কৌশলটি করেছে।
অবশেষে, নেভিগেশন ঘটানোর জন্য, আমাদের অবশ্যই আমাদের পূর্বে সংজ্ঞায়িত slideTo()
পদ্ধতিগুলিকে কল করতে হবে যা আমরা শেষ ডেমোতে ব্যবহার করেছি।
track.ontouchend = function(event) {
pageMove(event);
if (slideDirection == 'left') {
slideTo('products-page');
} else if (slideDirection == 'right') {
slideTo('home-page');
}
}
ঘূর্ণায়মান
এর পরে, আসুন এই ডেমোতে ব্যবহৃত রোটেট অ্যানিমেশনটি একবার দেখে নেওয়া যাক। যে কোনো সময়, "যোগাযোগ" মেনু বিকল্পে ট্যাপ করে বিপরীত দিকটি প্রকাশ করতে আপনি বর্তমানে যে পৃষ্ঠাটি দেখছেন সেটি 180 ডিগ্রি ঘোরাতে পারেন। আবার, onclick
একটি ট্রানজিশন ক্লাস বরাদ্দ করতে এটি শুধুমাত্র CSS এর কয়েকটি লাইন এবং কিছু জাভাস্ক্রিপ্ট নেয়। দ্রষ্টব্য: রোটেট ট্রানজিশনটি অ্যান্ড্রয়েডের বেশিরভাগ সংস্করণে সঠিকভাবে রেন্ডার করা হয় না কারণ এতে 3D CSS রূপান্তর ক্ষমতা নেই। দুর্ভাগ্যবশত, ফ্লিপ উপেক্ষা করার পরিবর্তে, অ্যান্ড্রয়েড পৃষ্ঠাটিকে ফ্লিপ করার পরিবর্তে ঘুরিয়ে "কার্টহুইল" দূরে সরিয়ে দেয়। সমর্থনের উন্নতি না হওয়া পর্যন্ত আমরা এই রূপান্তরটি সামান্য ব্যবহার করার পরামর্শ দিই।
মার্কআপ (সামনে এবং পিছনের মৌলিক ধারণা):
<div id="front" class="normal">
...
</div>
<div id="back" class="flipped">
<div id="contact-page" class="page">
<h1>Contact Page</h1>
</div>
</div>
জাভাস্ক্রিপ্ট:
function flip(id) {
// get a handle on the flippable region
var front = getElement('front');
var back = getElement('back');
// again, just a simple way to see what the state is
var classes = front.className.split(' ');
var flipped = classes.indexOf('flipped');
if (flipped >= 0) {
// already flipped, so return to original
front.className = 'normal';
back.className = 'flipped';
FLIPPED = false;
} else {
// do the flip
front.className = 'flipped';
back.className = 'normal';
FLIPPED = true;
}
}
সিএসএস:
/*----------------------------flip transition */
#back,
#front {
position: absolute;
width: 100%;
height: 100%;
-webkit-backface-visibility: hidden;
-webkit-transition-duration: .5s;
-webkit-transform-style: preserve-3d;
}
.normal {
-webkit-transform: rotateY(0deg);
}
.flipped {
-webkit-user-select: element;
-webkit-transform: rotateY(180deg);
}
ডিবাগিং হার্ডওয়্যার ত্বরণ
এখন যেহেতু আমরা আমাদের মৌলিক ট্রানজিশনগুলি কভার করেছি, আসুন কীভাবে তারা কাজ করে এবং সংমিশ্রিত হয় তার মেকানিক্সটি একবার দেখে নেওয়া যাক।
এই জাদুকরী ডিবাগিং সেশনটি ঘটানোর জন্য, আসুন কয়েকটি ব্রাউজার এবং আপনার পছন্দের IDE চালু করি। কিছু ডিবাগিং এনভায়রনমেন্ট ভেরিয়েবল ব্যবহার করতে কমান্ড লাইন থেকে প্রথমে Safari শুরু করুন। আমি ম্যাকে আছি, তাই আপনার ওএসের উপর ভিত্তি করে কমান্ডগুলি ভিন্ন হতে পারে। টার্মিনাল খুলুন এবং নিম্নলিখিত টাইপ করুন:
- $> রপ্তানি করুন CA_COLOR_OPAQUE=1
- $> রপ্তানি CA_LOG_MEMORY_USAGE=1
- $> /Applications/Safari.app/Contents/MacOS/Safari
এটি কয়েকটি ডিবাগিং সাহায্যকারীর সাথে সাফারি শুরু করে। CA_COLOR_OPAQUE আমাদের দেখায় কোন উপাদানগুলি আসলে সংমিশ্রিত বা ত্বরিত। CA_LOG_MEMORY_USAGE আমাদের দেখায় যে ব্যাকিং স্টোরে আমাদের ড্রয়িং অপারেশন পাঠানোর সময় আমরা কতটা মেমরি ব্যবহার করছি। এটি আপনাকে বলে যে আপনি মোবাইল ডিভাইসে ঠিক কতটা চাপ দিচ্ছেন এবং সম্ভবত আপনার জিপিইউ ব্যবহার লক্ষ্য ডিভাইসের ব্যাটারিকে কীভাবে নিঃশেষ করতে পারে তার ইঙ্গিত দেয়।
এখন ক্রোম ফায়ার করা যাক যাতে আমরা প্রতি সেকেন্ডে কিছু ভাল ফ্রেম (FPS) তথ্য দেখতে পারি:
- গুগল ক্রোম ওয়েব ব্রাউজার খুলুন।
- URL বারে, about:flags টাইপ করুন।
- কয়েকটি আইটেম নিচে স্ক্রোল করুন এবং FPS কাউন্টারের জন্য "সক্ষম করুন" এ ক্লিক করুন।
আপনি যদি Chrome এর আপনার স্যুপ আপ সংস্করণে এই পৃষ্ঠাটি দেখেন, আপনি উপরের বাম দিকের কোণায় লাল FPS কাউন্টার দেখতে পাবেন।
এইভাবে আমরা জানি হার্ডওয়্যার ত্বরণ চালু আছে। এটি আমাদের একটি ধারণা দেয় যে কীভাবে অ্যানিমেশন চলে এবং আপনার যদি কোনও ফাঁস থাকে (একটানা চলমান অ্যানিমেশনগুলি বন্ধ করা উচিত)।
হার্ডওয়্যার ত্বরণকে বাস্তবে কল্পনা করার আরেকটি উপায় হল যদি আপনি সাফারিতে একই পৃষ্ঠাটি খোলেন (আমি উপরে উল্লিখিত পরিবেশের ভেরিয়েবল সহ)। প্রতিটি ত্বরিত DOM উপাদানের একটি লাল আভা থাকে। এটি আমাদের দেখায় ঠিক কি স্তর দ্বারা সংমিশ্রিত হচ্ছে। লক্ষ্য করুন সাদা নেভিগেশন লাল নয় কারণ এটি ত্বরিত হয় না।
Chrome-এর জন্য একটি অনুরূপ সেটিং প্রায়:পতাকা "কম্পোজিটেড রেন্ডার লেয়ার বর্ডার"-এ পাওয়া যায়।
সংমিশ্রিত স্তরগুলি দেখার আরেকটি দুর্দান্ত উপায় হল এই মোডটি প্রয়োগ করার সময় ওয়েবকিট পতনশীল পাতার ডেমো দেখা।
এবং পরিশেষে, আমাদের অ্যাপ্লিকেশনের গ্রাফিক্স হার্ডওয়্যার কার্যকারিতা সত্যিই বোঝার জন্য, আসুন মেমরি কীভাবে গ্রাস করা হচ্ছে তা একবার দেখে নেওয়া যাক। এখানে আমরা দেখতে পাচ্ছি যে আমরা ম্যাক ওএস-এর কোরঅ্যানিমেশন বাফারগুলিতে 1.38MB অঙ্কন নির্দেশাবলী পুশ করছি। কোর অ্যানিমেশন মেমরি বাফারগুলি OpenGL ES এবং GPU-এর মধ্যে ভাগ করা হয় যাতে আপনি স্ক্রিনে দেখতে পান এমন চূড়ান্ত পিক্সেল তৈরি করতে পারেন।
যখন আমরা ব্রাউজার উইন্ডোর আকার পরিবর্তন করি বা বড় করি, তখন আমরা মেমরিটিও প্রসারিত দেখতে পাই।
আপনি সঠিক মাত্রায় ব্রাউজারটির আকার পরিবর্তন করলেই এটি আপনাকে আপনার মোবাইল ডিভাইসে কীভাবে মেমরি ব্যবহার করা হচ্ছে তার একটি ধারণা দেয়। আপনি যদি আইফোন পরিবেশের জন্য ডিবাগিং বা পরীক্ষা করছেন তাহলে 480px দ্বারা 320px আকার পরিবর্তন করুন। আমরা এখন বুঝতে পারি হার্ডওয়্যার ত্বরণ কিভাবে কাজ করে এবং এটি ডিবাগ করতে কি লাগে। এটি সম্পর্কে পড়া এক জিনিস, কিন্তু আসলে GPU মেমরি বাফারগুলি দৃশ্যমানভাবে কাজ করা দেখতে জিনিসগুলিকে দৃষ্টিকোণে নিয়ে আসে।
পর্দার পিছনে: আনয়ন এবং ক্যাশিং
এখন আমাদের পৃষ্ঠা এবং রিসোর্স ক্যাশিংকে পরবর্তী স্তরে নিয়ে যাওয়ার সময়। অনেকটা JQuery মোবাইল এবং অনুরূপ ফ্রেমওয়ার্ক ব্যবহার করার পদ্ধতির মতো, আমরা সমসাময়িক AJAX কলগুলির সাথে আমাদের পৃষ্ঠাগুলিকে প্রাক-আনয়ন এবং ক্যাশে করতে যাচ্ছি।
আসুন কয়েকটি মূল মোবাইল ওয়েব সমস্যা এবং আমাদের কেন এটি করতে হবে তার কারণগুলি সমাধান করি:
- নিয়ে আসা: আমাদের পৃষ্ঠাগুলি প্রাক-আনয়ন ব্যবহারকারীদের অ্যাপটিকে অফলাইনে নেওয়ার অনুমতি দেয় এবং নেভিগেশন ক্রিয়াগুলির মধ্যে কোনও অপেক্ষা করতে দেয় না। অবশ্যই, যখন ডিভাইসটি অনলাইনে আসে তখন আমরা ডিভাইসের ব্যান্ডউইথকে শ্বাসরোধ করতে চাই না, তাই আমাদের এই বৈশিষ্ট্যটি সামান্য ব্যবহার করতে হবে।
- ক্যাশিং: এর পরে, এই পৃষ্ঠাগুলি আনা এবং ক্যাশে করার সময় আমরা একটি সমবর্তী বা অ্যাসিঙ্ক্রোনাস পদ্ধতি চাই। আমাদের স্থানীয় স্টোরেজ ব্যবহার করতে হবে (যেহেতু এটি ডিভাইসগুলির মধ্যে ভালভাবে সমর্থিত) যা দুর্ভাগ্যবশত অ্যাসিঙ্ক্রোনাস নয়।
- AJAX এবং প্রতিক্রিয়া পার্সিং: DOM-এ AJAX প্রতিক্রিয়া সন্নিবেশ করার জন্য innerHTML() ব্যবহার করা বিপজ্জনক (এবং অবিশ্বস্ত ?)। আমরা পরিবর্তে AJAX প্রতিক্রিয়া সন্নিবেশ এবং সমসাময়িক কল পরিচালনার জন্য একটি নির্ভরযোগ্য প্রক্রিয়া ব্যবহার করি। এছাড়াও আমরা
xhr.responseText
পার্স করার জন্য HTML5 এর কিছু নতুন বৈশিষ্ট্য ব্যবহার করি।
স্লাইড, ফ্লিপ এবং রোটেট ডেমো থেকে কোড তৈরি করে, আমরা কিছু গৌণ পৃষ্ঠা যুক্ত করে এবং তাদের সাথে লিঙ্ক করে শুরু করি। তারপরে আমরা লিঙ্কগুলি পার্স করব এবং ফ্লাইতে ট্রানজিশন তৈরি করব।
এখানে ফেচ এবং ক্যাশে ডেমো দেখুন।
আপনি দেখতে পাচ্ছেন, আমরা এখানে শব্দার্থিক মার্কআপ ব্যবহার করছি। শুধু অন্য পৃষ্ঠার একটি লিঙ্ক. চাইল্ড পৃষ্ঠাটি তার অভিভাবক হিসাবে একই নোড/শ্রেণীর কাঠামো অনুসরণ করে। আমরা এটিকে আরও এক ধাপ এগিয়ে নিয়ে যেতে পারি এবং "পৃষ্ঠা" নোড ইত্যাদির জন্য ডেটা-* অ্যাট্রিবিউট ব্যবহার করতে পারি। এবং এখানে একটি পৃথক এইচটিএমএল ফাইল (/demo2/home-detail.html) এ অবস্থিত বিস্তারিত পৃষ্ঠা (শিশু) রয়েছে যা হবে লোড করা হয়েছে, ক্যাশে করা হয়েছে এবং অ্যাপ লোডে পরিবর্তনের জন্য সেট আপ করা হয়েছে।
<div id="home-page" class="page">
<h1>Home Page</h1>
<a href="demo2/home-detail.html" class="fetch">Find out more about the home page!</a>
</div>
এখন জাভাস্ক্রিপ্ট দেখে নেওয়া যাক। সরলতার জন্য, আমি কোডের বাইরে কোনো সাহায্যকারী বা অপ্টিমাইজেশান রেখে যাচ্ছি। আমরা এখানে যা করছি তা হল একটি নির্দিষ্ট অ্যারের মাধ্যমে লুপ করা DOM নোডের লিঙ্কগুলি বের করে আনতে এবং ক্যাশে করার জন্য। দ্রষ্টব্য—এই ডেমোর জন্য, এই পদ্ধতিটি fetchAndCache()
পৃষ্ঠা লোডের উপর কল করা হচ্ছে। যখন আমরা নেটওয়ার্ক সংযোগ শনাক্ত করি এবং কখন এটি কল করা উচিত তা নির্ধারণ করে আমরা পরবর্তী বিভাগে এটি পুনরায় কাজ করি।
var fetchAndCache = function() {
// iterate through all nodes in this DOM to find all mobile pages we care about
var pages = document.getElementsByClassName('page');
for (var i = 0; i < pages.length; i++) {
// find all links
var pageLinks = pages[i].getElementsByTagName('a');
for (var j = 0; j < pageLinks.length; j++) {
var link = pageLinks[j];
if (link.hasAttribute('href') &&
//'#' in the href tells us that this page is already loaded in the DOM - and
// that it links to a mobile transition/page
!(/[\#]/g).test(link.href) &&
//check for an explicit class name setting to fetch this link
(link.className.indexOf('fetch') >= 0)) {
//fetch each url concurrently
var ai = new ajax(link,function(text,url){
//insert the new mobile page into the DOM
insertPages(text,url);
});
ai.doGet();
}
}
}
};
আমরা “AJAX” অবজেক্ট ব্যবহারের মাধ্যমে যথাযথ অ্যাসিঙ্ক্রোনাস পোস্ট-প্রসেসিং নিশ্চিত করি। HTML5 অফলাইনের সাথে ওয়ার্কিং অফ দ্য গ্রিডে AJAX কলের মধ্যে স্থানীয় স্টোরেজ ব্যবহার করার আরও উন্নত ব্যাখ্যা রয়েছে। এই উদাহরণে, আপনি প্রতিটি অনুরোধে ক্যাশে করার প্রাথমিক ব্যবহার এবং সার্ভারটি একটি সফল (200) প্রতিক্রিয়া ছাড়া অন্য কিছু ফেরত দিলে ক্যাশে করা বস্তুগুলি সরবরাহ করতে দেখেন।
function processRequest () {
if (req.readyState == 4) {
if (req.status == 200) {
if (supports_local_storage()) {
localStorage[url] = req.responseText;
}
if (callback) callback(req.responseText,url);
} else {
// There is an error of some kind, use our cached copy (if available).
if (!!localStorage[url]) {
// We have some data cached, return that to the callback.
callback(localStorage[url],url);
return;
}
}
}
}
দুর্ভাগ্যবশত, যেহেতু লোকাল স্টোরেজ অক্ষর এনকোডিংয়ের জন্য UTF-16 ব্যবহার করে, তাই প্রতিটি একক বাইট 2 বাইট হিসাবে সংরক্ষণ করা হয় যা আমাদের স্টোরেজ সীমা 5MB থেকে 2.6MB মোট নিয়ে আসে। অ্যাপ্লিকেশন ক্যাশে সুযোগের বাইরে এই পৃষ্ঠাগুলি/মার্কআপগুলি আনা এবং ক্যাশে করার সম্পূর্ণ কারণ পরবর্তী বিভাগে প্রকাশ করা হয়েছে৷
HTML5 এর সাথে iframe উপাদানে সাম্প্রতিক অগ্রগতির সাথে, আমাদের কাছে এখন আমাদের AJAX কল থেকে ফিরে আসা responseText
পার্স করার একটি সহজ এবং কার্যকর উপায় রয়েছে। প্রচুর 3000-লাইন জাভাস্ক্রিপ্ট পার্সার এবং রেগুলার এক্সপ্রেশন রয়েছে যা স্ক্রিপ্ট ট্যাগ ইত্যাদি সরিয়ে দেয়। কিন্তু ব্রাউজারকে কেন এটি সবচেয়ে ভাল করতে দেয় না? এই উদাহরণে, আমরা একটি অস্থায়ী লুকানো আইফ্রেমে responseText
লিখতে যাচ্ছি। আমরা HTML5 "স্যান্ডবক্স" অ্যাট্রিবিউট ব্যবহার করছি যা স্ক্রিপ্ট অক্ষম করে এবং অনেক নিরাপত্তা বৈশিষ্ট্য অফার করে...
বিশেষত্ব থেকে: স্যান্ডবক্স অ্যাট্রিবিউট, নির্দিষ্ট করা হলে, আইফ্রেম দ্বারা হোস্ট করা যেকোনো সামগ্রীতে অতিরিক্ত বিধিনিষেধের একটি সেট সক্ষম করে৷ এর মান অবশ্যই ASCII কেস-সংবেদনশীল অনন্য স্থান-বিচ্ছিন্ন টোকেনগুলির একটি ক্রমবিহীন সেট হতে হবে। অনুমোদিত মান হল অনুমতি-ফর্ম, অনুমতি-একই-উৎপত্তি, মঞ্জুরি-স্ক্রিপ্ট এবং মঞ্জুরি-শীর্ষ-নেভিগেশন। যখন অ্যাট্রিবিউট সেট করা হয়, তখন বিষয়বস্তুটিকে একটি অনন্য উত্স থেকে আসা হিসাবে বিবেচনা করা হয়, ফর্ম এবং স্ক্রিপ্টগুলি অক্ষম করা হয়, লিঙ্কগুলিকে অন্যান্য ব্রাউজিং প্রসঙ্গে লক্ষ্য করা থেকে বাধা দেওয়া হয় এবং প্লাগইনগুলি অক্ষম করা হয়৷
var insertPages = function(text, originalLink) {
var frame = getFrame();
//write the ajax response text to the frame and let
//the browser do the work
frame.write(text);
//now we have a DOM to work with
var incomingPages = frame.getElementsByClassName('page');
var pageCount = incomingPages.length;
for (var i = 0; i < pageCount; i++) {
//the new page will always be at index 0 because
//the last one just got popped off the stack with appendChild (below)
var newPage = incomingPages[0];
//stage the new pages to the left by default
newPage.className = 'page stage-left';
//find out where to insert
var location = newPage.parentNode.id == 'back' ? 'back' : 'front';
try {
// mobile safari will not allow nodes to be transferred from one DOM to another so
// we must use adoptNode()
document.getElementById(location).appendChild(document.adoptNode(newPage));
} catch(e) {
// todo graceful degradation?
}
}
};
সাফারি সঠিকভাবে একটি নথি থেকে অন্য নথিতে একটি নোড সরাতে অস্বীকার করে। একটি ত্রুটি উত্থাপিত হয় যদি নতুন চাইল্ড নোড একটি ভিন্ন নথিতে তৈরি করা হয়। তাই এখানে আমরা adoptNode
ব্যবহার করি এবং সব ঠিক আছে।
তাহলে আইফ্রেম কেন? কেন শুধু innerHTML ব্যবহার করবেন না? যদিও ইনারএইচটিএমএল এখন HTML5 স্পেকের অংশ, এটি একটি বিপজ্জনক অভ্যাস একটি সার্ভার থেকে প্রতিক্রিয়া (মন্দ বা ভাল) একটি আনচেক করা এলাকায় প্রবেশ করানো। এই নিবন্ধটি লেখার সময়, আমি innerHTML ছাড়া অন্য কিছু ব্যবহার করে কাউকে খুঁজে পাইনি। আমি জানি JQuery এটির মূলে এটি ব্যবহার করে শুধুমাত্র ব্যতিক্রমের জন্য একটি যুক্ত ফলব্যাক সহ। এবং JQuery মোবাইল এটিও ব্যবহার করে। যাইহোক, আমি innerHTML "এলোমেলোভাবে কাজ করা বন্ধ করে" সম্পর্কে কোন ভারী পরীক্ষা করিনি, তবে এটি প্রভাবিত করে এমন সমস্ত প্ল্যাটফর্মগুলি দেখতে খুব আকর্ষণীয় হবে। কোন পন্থা বেশি পারফরম্যান্স তা দেখতেও আকর্ষণীয় হবে... আমি উভয় পক্ষের দাবি শুনেছি।
নেটওয়ার্ক প্রকার সনাক্তকরণ, পরিচালনা এবং প্রোফাইলিং
এখন যেহেতু আমাদের ওয়েব অ্যাপটি বাফার (বা ভবিষ্যদ্বাণীমূলক ক্যাশে) করার ক্ষমতা আছে, তাই আমাদের অবশ্যই সঠিক সংযোগ সনাক্তকরণ বৈশিষ্ট্যগুলি প্রদান করতে হবে যা আমাদের অ্যাপটিকে আরও স্মার্ট করে তোলে৷ এখানেই মোবাইল অ্যাপ ডেভেলপমেন্ট অনলাইন/অফলাইন মোড এবং সংযোগের গতির প্রতি অত্যন্ত সংবেদনশীল হয়ে ওঠে। নেটওয়ার্ক তথ্য API লিখুন। যখনই আমি একটি উপস্থাপনায় এই বৈশিষ্ট্যটি দেখাই, দর্শকদের মধ্যে কেউ একজন তাদের হাত তুলে জিজ্ঞাসা করে "আমি এটি কিসের জন্য ব্যবহার করব?"। তাই এখানে একটি অত্যন্ত স্মার্ট মোবাইল ওয়েব অ্যাপ সেটআপ করার একটি সম্ভাব্য উপায় রয়েছে৷
প্রথমে বিরক্তিকর সাধারণ জ্ঞানের দৃশ্যকল্প... একটি উচ্চ-গতির ট্রেনে মোবাইল ডিভাইস থেকে ওয়েবের সাথে ইন্টারঅ্যাক্ট করার সময়, নেটওয়ার্কটি বিভিন্ন মুহুর্তে খুব ভালভাবে চলে যেতে পারে এবং বিভিন্ন ভৌগোলিক বিভিন্ন ট্রান্সমিশন গতিকে সমর্থন করতে পারে (যেমন, HSPA বা 3G উপলব্ধ হতে পারে কিছু শহুরে এলাকা, কিন্তু প্রত্যন্ত অঞ্চলে অনেক ধীরগতির 2G প্রযুক্তি সমর্থন করতে পারে)। নিম্নলিখিত কোডটি বেশিরভাগ সংযোগ পরিস্থিতির ঠিকানা দেয়।
নিম্নলিখিত কোড প্রদান করে:
-
applicationCache
মাধ্যমে অফলাইন অ্যাক্সেস। - বুকমার্ক করা এবং অফলাইন কিনা তা সনাক্ত করে।
- অফলাইন থেকে অনলাইনে স্যুইচ করার সময় সনাক্ত করে এবং এর বিপরীতে।
- ধীরগতির সংযোগ সনাক্ত করে এবং নেটওয়ার্ক প্রকারের উপর ভিত্তি করে সামগ্রী আনে।
আবার, এই সমস্ত বৈশিষ্ট্য খুব কম কোড প্রয়োজন. প্রথমে আমরা আমাদের ইভেন্ট এবং লোডিং পরিস্থিতি সনাক্ত করি:
window.addEventListener('load', function(e) {
if (navigator.onLine) {
// new page load
processOnline();
} else {
// the app is probably already cached and (maybe) bookmarked...
processOffline();
}
}, false);
window.addEventListener("offline", function(e) {
// we just lost our connection and entered offline mode, disable eternal link
processOffline(e.type);
}, false);
window.addEventListener("online", function(e) {
// just came back online, enable links
processOnline(e.type);
}, false);
উপরের ইভেন্টলিসটেনার্সে, আমাদের অবশ্যই আমাদের কোডটি জানাতে হবে যদি এটি কোনও ইভেন্ট বা প্রকৃত পৃষ্ঠার অনুরোধ বা রিফ্রেশ থেকে কল করা হয়। প্রধান কারণ হল অনলাইন এবং অফলাইন মোডগুলির মধ্যে স্যুইচ করার সময় বডি onload
ইভেন্টটি বরখাস্ত করা হবে না৷
এর পরে, আমাদের কাছে একটি ononline
বা onload
ইভেন্টের জন্য একটি সহজ চেক আছে। অফলাইন থেকে অনলাইনে স্যুইচ করার সময় এই কোডটি নিষ্ক্রিয় লিঙ্কগুলিকে পুনরায় সেট করে, কিন্তু যদি এই অ্যাপটি আরও পরিশীলিত হয়, তাহলে আপনি এমন যুক্তি সন্নিবেশ করাতে পারেন যা সামগ্রী ফেরানো আবার শুরু করবে বা বিরতিহীন সংযোগের জন্য UX পরিচালনা করবে৷
function processOnline(eventType) {
setupApp();
checkAppCache();
// reset our once disabled offline links
if (eventType) {
for (var i = 0; i < disabledLinks.length; i++) {
disabledLinks[i].onclick = null;
}
}
}
একই processOffline()
ক্ষেত্রেও যায়। এখানে আপনি অফলাইন মোডের জন্য আপনার অ্যাপকে ম্যানিপুলেট করবেন এবং পর্দার আড়ালে যে কোনো লেনদেন পুনরুদ্ধার করার চেষ্টা করবেন। নীচের এই কোডটি আমাদের সমস্ত বাহ্যিক লিঙ্কগুলিকে খনন করে এবং সেগুলিকে নিষ্ক্রিয় করে—আমাদের অফলাইন অ্যাপে ব্যবহারকারীদের চিরতরে আটকে রাখে মুহাহাহা!
function processOffline() {
setupApp();
// disable external links until we come back - setting the bounds of app
disabledLinks = getUnconvertedLinks(document);
// helper for onlcick below
var onclickHelper = function(e) {
return function(f) {
alert('This app is currently offline and cannot access the hotness');return false;
}
};
for (var i = 0; i < disabledLinks.length; i++) {
if (disabledLinks[i].onclick == null) {
//alert user we're not online
disabledLinks[i].onclick = onclickHelper(disabledLinks[i].href);
}
}
}
ঠিক আছে, তাই ভাল জিনিস. এখন যেহেতু আমাদের অ্যাপটি জানে যে এটি কোন সংযুক্ত অবস্থায় আছে, আমরা এটি অনলাইনে থাকাকালীন সংযোগের ধরনও পরীক্ষা করতে পারি এবং সেই অনুযায়ী সামঞ্জস্য করতে পারি। আমি প্রতিটি সংযোগের জন্য মন্তব্যে সাধারণ উত্তর আমেরিকান সরবরাহকারীদের ডাউনলোড এবং বিলম্ব তালিকাভুক্ত করেছি।
function setupApp(){
// create a custom object if navigator.connection isn't available
var connection = navigator.connection || {'type':'0'};
if (connection.type == 2 || connection.type == 1) {
//wifi/ethernet
//Coffee Wifi latency: ~75ms-200ms
//Home Wifi latency: ~25-35ms
//Coffee Wifi DL speed: ~550kbps-650kbps
//Home Wifi DL speed: ~1000kbps-2000kbps
fetchAndCache(true);
} else if (connection.type == 3) {
//edge
//ATT Edge latency: ~400-600ms
//ATT Edge DL speed: ~2-10kbps
fetchAndCache(false);
} else if (connection.type == 2) {
//3g
//ATT 3G latency: ~400ms
//Verizon 3G latency: ~150-250ms
//ATT 3G DL speed: ~60-100kbps
//Verizon 3G DL speed: ~20-70kbps
fetchAndCache(false);
} else {
//unknown
fetchAndCache(true);
}
}
আমাদের fetchAndCache প্রক্রিয়াতে আমরা অনেকগুলি সামঞ্জস্য করতে পারি, কিন্তু আমি এখানে যা করেছি তা হল একটি প্রদত্ত সংযোগের জন্য অসিঙ্ক্রোনাস (সত্য) বা সিঙ্ক্রোনাস (মিথ্যা) সংস্থানগুলি আনার জন্য।
এজ (সিঙ্ক্রোনাস) অনুরোধের সময়রেখা
ওয়াইফাই (অ্যাসিনক্রোনাস) অনুরোধের সময়রেখা
এটি ধীর বা দ্রুত সংযোগের উপর ভিত্তি করে ব্যবহারকারীর অভিজ্ঞতা সামঞ্জস্যের অন্তত কিছু পদ্ধতির জন্য অনুমতি দেয়। এটা কোনোভাবেই শেষ-সব-সকল সমাধান নয়। আরেকটি করণীয় হল একটি লোডিং মডেল তুলে দেওয়া যখন একটি লিঙ্কে ক্লিক করা হয় (ধীর সংযোগে) যখন অ্যাপটি এখনও সেই লিঙ্কটির পৃষ্ঠাটি ব্যাকগ্রাউন্ডে আনতে পারে। এখানে সবচেয়ে বড় বিষয় হল লেটেন্সি কমিয়ে দেওয়া এবং সর্বশেষ এবং সর্বশ্রেষ্ঠ HTML5-এর সাথে ব্যবহারকারীর সংযোগের সম্পূর্ণ ক্ষমতা ব্যবহার করা। নেটওয়ার্ক সনাক্তকরণ ডেমো এখানে দেখুন ।
উপসংহার
মোবাইল HTML5 অ্যাপ্লিকেশানগুলির রাস্তার নিচে যাত্রা সবে শুরু হয়েছে৷ এখন আপনি শুধুমাত্র HTML5 এর আশেপাশে নির্মিত একটি মোবাইল "ফ্রেমওয়ার্ক" এর খুব সহজ এবং মৌলিক ভিত্তি দেখতে পাচ্ছেন এবং এটি প্রযুক্তি সমর্থন করছে। আমি মনে করি বিকাশকারীদের জন্য এই বৈশিষ্ট্যগুলির সাথে কাজ করা এবং তাদের মূলে এড্রেস করা এবং একটি মোড়ক দ্বারা মুখোশ না করা গুরুত্বপূর্ণ।