লেখক: مارভিন ফ্রাশে
এই বছর রিয়েক্টের বছর বলে মনে হচ্ছে। আপনি হুকস (Hooks) নামক নতুন কিলার ফিচারের কথা শোনেছেন যা 16.7-alpha.0 সংস্করণে আসছে। আপনি টাইম স্লাইসিং (Time Slicing) বা সাসপেন্স (Suspense) এর মতো অন্যান্য চমৎকার জিনিসের কথাও শোনে থাকতে পারেন।
এই লেখাটি নতুন ফিচারগুলো কীভাবে ব্যবহার করবেন তা বর্ণনা করার লক্ষ্য রাখে না, বরং এটি প্রমাণ করতে চায় যে সেগুলো কীভাবে তৈরি হতে পারে। শুধু আমরা womit খেলছি সেটি বোঝার জন্য।
এটি আমি যেভাবে ফিচারটি আবিষ্কার করেছিলাম ঠিক সেইভাবে লেখা। এটি সম্ভবত চিন্তা করা হয়েছিল না, কিন্তু এটি আমার বোঝার পথ ছিল।
পড়তে পাবেন:
- অ্যাসিনক্রোনাস জাভাস্ক্রিপ্ট এবং ইভেন্ট লুপ
- রিয়েক্টে বীজগাণিতিক প্রভাব (Algebraic Effects), উদাহরণসহ
- ফাইবার (Fiber) এবং রিয়েক্টের ফেজ (Phases)
কেন আমি এই পোস্টটি লিখলাম?
এই বিশেষ এবং পরীক্ষামূলক ফিচারটি আমাকে এই পোস্ট লিখতে বাধ্য করেছিল যা অ্যাসিনক্রোনাস অপারেশনকে সিঙ্ক্রোনাস এপিআই ব্যবহার করে করার অনুমতি দেয়:
const bulbasaur = ApiResource.read()?… কি? সিঙ্ক্রোনাস?!
রিয়েক্ট-ক্যাশ লাইব্রেরি অ্যাসিনক্রোনাস অপারেশনকে সিঙ্ক্রোনাস এপিআই দিয়ে ব্যবহার করার ক্ষমতা সৃষ্টি করে। এই ফিচারটিই আমাকে রিয়েক্ট কীভাবে हुडের নিচে কাজ করে তা শিখতে অনুপ্রাণিত করেছিল। ড্যান अब্রামোভ এবং অ্যান্ড্রু ক্লার্কের এই লাইব্রেরির প্রেজেন্টেশনটি এখানে:
এটি কীভাবে সম্ভব? সিঙ্ক্রোনাস কল ব্যবহার করে রিমোট ডেটা কীভাবে পেতে পারি?
চলুন এই উদাহরণে গভীরে যাই এবং রিয়েক্ট-ক্যাশ কীভাবে এই কার্যকারিতা বাস্তবায়ন করে এবং কীভাবে এটি কাজ করতে পারে তা বুঝতে চেষ্টা করি। এই গল্প শুরু হয় ফাইবার আর্কিটেকচারের সাথে।
জাভাস্ক্রিপ্ট অপারেশন নিয়ন্ত্রণ
ফাইবার আর্কিটেকচার রিয়েক্টকে টাস্ক এক্সিকিউশনের উপর নিয়ন্ত্রণ নেওয়ার অনুমতি দেয়। এটি রিয়েক্ট যে সমস্যা থেকে ভুগতেছিল সেগুলো সমাধান করার জন্য তৈরি হয়েছিল। এখানে দুটি সমস্যা আমার মনে পড়ে:
- নির্দিষ্ট ইভেন্টগুলিকে প্রাধান্য দেওয়া, যেমন ডেটা ফেচিংয়ের চেয়ে ব্যবহারকারীর ইনপুট
- রিয়েক্ট কম্পিউটেশনকে অ্যাসিনক্রোনাসভাবে বিভক্ত করে মূল থ্রেডের rendelkeযোগ্যতা বজায় রাখা এবং দীর্ঘ রেন্ডারিং প্রক্রিয়ার সময় এটি ব্লক হওয়া থেকে বাঁচানো
জাভাস্ক্রিপ্ট অ্যাপ্লিকেশনে স্টেট পরিবর্তন সৃষ্টি করে এমন সব কিছু — শুধু রিয়েক্ট নয় — অ্যাসিনক্রোনাস অপারেশনের কারণে হয়। এতে setTimeout, fetch, এবং ইভেন্ট লিসেনার অন্তর্ভুক্ত।
অ্যাসিনক্রোনাস অপারেশন একাধিক জাভাস্ক্রিপ্ট কোর কনসেপ্টের মাধ্যমে পরিচালিত হয়:
- টাস্ক (মাইক্রো, ম্যাক্রো, রেন্ডার ইত্যাদি)
- ইভেন্ট লুপ
- কলস্ট্যাক (callstack)
যদি আপনি এই ধারণাগুলোর সাথে পরিচিত না হন, তাহলে জেক আর্কিব্যাল্ডের এই ভিডিওটি দেখতে পারেন:
ফাইবারের সুবিধায়, ব্যবহারকারীর ইনপুট সমাধান হয় অন্যান্য অ্যাসিনক্রোনাস অপারেশন যেমন ফেচ কলের আগে।
এটি কীভাবে সম্ভব?
উপরোক্ত আর্কিব্যাল্ডের কথাবার্তা আমার নিজের লার্নিং পথের প্রথম পেভড স্টোন ছিল ইভেন্ট লুপ কীভাবে কাজ করে সে সম্পর্কে। তিনি বলেন মাইক্রো টাস্ক — যা প্রমিস এপিআইয়ের মাধ্যমে তৈরি হয় — পরবর্তী ম্যাক্রো টাস্কের পূর্বে এক্সিকিউট এবং ফ্লাশ হয়। এই প্রক্রিয়াটি setTimeout এর মতো কলব্যাক-ভিত্তিক পদ্ধতি ব্যবহার করে।
তাহলে, আপনি যদি আমার "ব্যবহারকারীর ইনপুট বনাম ডেটা ফেচিং" তুলনাটি মনে রাখেন, টিম কীভাবে fetch রেজোলিউশনকে onChange রেজোলিউশনের পরে করিয়েছিল?
এই কোনো কনসেপ্ট একই স্পেসিফিকেশনে (WhatWG / HTML5 / Ecma-262) ফিট করে না এবং ব্রাউজার বা জেএস ইঞ্জিনের মতো বিভিন্ন জায়গা থেকে প্রদান করা হয়।
আমরা কীভাবে একটি Promise-কে setTimeout-এর পরে রেজলভ করব?
এটি আমাকে সম্পূর্ণ বাজে লাগেছিল এবং এটি কীভাবে কাজ করতে পারে তার ধারণা পাওয়া খুব কঠিন ছিল। সত্যি কথা, এটি একটি উচ্চতর লেভেলে ঘটে।
পরে, আমি রিয়েক্ট র্যালিতে ব্র্যান্ডন ডেইলের অবিশ্বাস্য কথাবার্তা দেখেছিলাম। এটি নতুন টাইম স্লাইসিং এবং সাসপেন্স ফিচারগুলি উপস্থাপন করে যা রিয়েক্ট ফাইবার আর্কিটেকচারের 덕분에 শিপ করা হয়েছে:
ডেইল অনুযায়ী, ফাইবার সাধারণ জাভাস্ক্রিপ্ট কলস্ট্যাকের মতোই যেখানে স্ট্যাকের প্রতিটি আইটেমকে ফাইবার বলা হয়। এটি কলস্ট্যাক থেকে আলাদা যা ফ্রেম-এর উপর নির্ভর করে যা ফাংশন (+ মেটাডেটা)-কে প্রতিনিধিত্ব করে। বরং, একটি ফাইবার একটি কম্পোনেন্ট (+ মেটাডেটা)-কে প্রতিনিধিত্ব করে। একটি ফাইবারকে একটি কম্পোনেন্টের চারপাশে একটি বিশাল বক্স হিসেবে কল্পনা করুন যা তার সম্পর্কে সব কিছু জানে।
এই দুটি কনসেপ্টের মধ্যে একটি গুরুত্বপূর্ণ পার্থক্য রয়েছে।
প্রথম দিক থেকে, কলস্ট্যাক একটি ফাংশনালিটি যা নেটিভ পার্ট ড্রাইভিং জাভাস্ক্রিপ্ট কোড-এর ওপর তৈরি। এটি প্রতিটি জাভাস্ক্রিপ্ট ফাংশন কলকে স্ট্যাক করার লক্ষ্য রাখে এবং তাদের নিজস্বভাবে রান করে। প্রতিবার আমরা একটি ফাংশন কল করলে তা স্ট্যাকে যোগ হয়। কলস্ট্যাক ছাড়া আমাদের স্পষ্ট এবং বিস্তারিত এরর স্ট্যাকট্রেস পাওয়া যেতো না। এবং যেহেতু কলস্ট্যাক জাভাস্ক্রিপ্ট কোড থেকে অ্যাক্সেসযোগ্য নয়, তাই এর ওপর নিয়ন্ত্রণ নেওয়া বাস্তব릭ভাবে অসম্ভব এবং খুব কঠিন।
দूसरी ओर, ফাইবার — যেমন ফাইবারের একটি স্ট্যাক — একই কনসেপ্টকে প্রতিনিধিত্ব করে, কিন্তু জাভাস্ক্রিপ্ট কোডে তৈরি। সবচেয়ে ছোট ইউনিট ফাংশন নয়, বরং একটি কম্পোনেন্ট। এটি আসলে একটি জাভাস্ক্রিপ্ট ইউনিভার্সে রান করে।
ফাইবার আর্কিটেকচার সম্পূর্ণরূপে জাভাস্ক্রিপ্টে বিল্ড হওয়ার সত্যিটি বোঝায় যে আমরা এটি ব্যবহার করতে পারি, অ্যাক্সেস করতে পারি এবং মডিফাই করতে পারি। আমরা স্ট্যান্ডার্ড জাভাস্ক্রিপ্ট ব্যবহার করে এতে কাজ করতে পারি।
যে चीজ আমাকে ভুল দিকে নিয়ে গিয়েছিল সেটি ছিল আমি চিন্তা করতাম রিয়েক্ট জাভাস্ক্রিপ্টের অভ্যন্তরীণ কাজ করার পদ্ধতিকে কাট-অফ করার একটি ওয়ার্কঅরাউন্ড ব্যবহার করছে। এটি সত্য নয়। ফাইবারগুলি সadă জাভাস্ক্রিপ্ট অবজেক্ট যা রিয়েক্ট কম্পোনেন্ট সম্পর্কে তথ্য ধারণ করে এবং যেগুলো তাদের লাইফসাইকলের সাথে ইন্টারঅ্যাক্ট করতে পারে। এটি শুধুমাত্র রিয়েক্টের অভ্যন্তরীণ ফাংশনালিটিতে কাজ করতে পারে।
উদ্দেশ্য নहीं জাভাস্ক্রিপ্ট কীভাবে কাজ করা উচিত তা পুনর্নির্ধারণ করা, যেমন বলে দেওয়া যে fetch মাইক্রোটাস্ক রেজোলিউশন কলব্যাক টাস্কের আগে এক্সিকিউট হওয়া উচিত। এটি আরও spesifically সম্পর্কিত যে কোন রিয়েক্ট মেথড কল করা উচিত বা না একটি নির্দিষ্ট কনটেক্সটে, যেমন বিভিন্ন লাইফসাইকেল মেথড কলকে ইন্টারাপ্ট করা।
এইচ! আপনি বলছেন ফাইবার একটি রিয়েক্ট অ্যাপে সব কিছু নিয়ন্ত্রণ করতে পারে? কিন্তু একটি কম্পোনেন্ট কীভাবে রিয়েক্টকে বলতে পারে কিছুই না করার জন্য?
বীজগাণিতিক প্রভাব (Algebraic Effects), হ্যাঁ, কিন্তু জাভাস্ক্রিপ্টে দয়া করে
ফাইবার আর্কিটেকচারের কারণে রিয়েক্ট কম্পোনেন্টগুলো নিয়ন্ত্রণ করতে পারে এবং জানতে পারে কোন কম্পোনেন্ট চলছে। এখন যা বাকি रह গেছে সেটি হলো রিয়েক্টকে জানানোর একটি উপায় যে একটি নির্দিষ্ট কম্পোনেন্টের জন্য কিছু পরিবর্তন হয়েছে, যাতে সেটি এই পরিবর্তনটি হ্যান্ডেল করতে পারে।
এখানেই বীজগাণিতিক প্রভাব (algebraic effects) 등장 করে।
বীজগাণিতিক প্রভাব জাভাস্ক্রিপ্টে কিছু এক্সিস্ট করে না। আমি একটি উচ্চতর স্তরের ব্যাখ্যা দিয়ে ব্যাখ্যা করার চেষ্টা করব।
বীজগাণিতিক প্রভাব একটি কনসেপ্ট যা কিছু ইনফরমেশন কোথাও পাঠানোর অনুমতি দেয়, কিছুটা একটি ডিসপ্যাচারের মতো। ধারণা হলো একটি নির্দিষ্ট ফাংশন কল করা যা বর্তমানে চলমান ফাংশনকে একটি নির্দিষ্ট পজিশনে ইন্টারাপ্ট করবে যাতে একটি পেরেন্ট ফাংশন একটি কম্পিউটেশন হ্যান্ডেল করতে পারে। যখন পেরেন্ট কম্পিউটেশন শেষ হয়, এটি প্রোগ্রামটি শুরুতে যেখানে ইনফরমেশন পাঠানো হয়েছিল সেটি রিজিউম করতে পারে।
OCaml বা Eff এর মতো কিছু ভাষা এই ফিচারটি নেটিভলি পায়। এটি একটি খুব আকর্ষণীয় অ্যাবস্ট্রাকশন যেহেতু ইমপ্লিমেন্টেশন ডিটেইলস শুধু পেরেন্টের ওপর নির্ভর করে:
জাভাস্ক্রিপ্টে এমন একটি ফিচার থাকা কতটো অসাধারণ হত?
রিয়েক্ট টিম জাভাস্ক্রিপ্ট try/catch ব্লকের সাথে কাজ করে একটি রিয়েক্ট কনটেক্সটে অনুরূপ একটি পদ্ধতি তৈরি করেছে। ডেইল অনুযায়ী, এটি জাভাস্ক্রিপ্টে উপলব্ধ সবচেয়ে কাছাকাছি কনসেপ্ট।
কিছু থ্রো (throw) করার মাধ্যমে ইনফরমেশন কোথাও পেরেন্টের কাছে পাঠানো যায়। প্রথম পেরেন্ট যেটি ইনফরমেশনটি ক্যাচ করে সেটি এটিকে ডিল করতে পারে এবং সেটির ওপর কম্পিউটেশন করতে পারে।
হাজার কথার চেয়ে একটি উদাহরণ ভালো
নিচের কোডটি কল্পনা করুন যা Bulbasaur ফেচ করার চেষ্টা করে একটি সিঙ্ক্রোনাস এপিআই ব্যবহার করে:
এই কোডটি অদ্ভুত লাগতে পারে কারণ সিঙ্ক্রোনাস এপিআই দিয়ে ডেটা ফেচ করা সাধারণ নয়। চলুন customFetch ফাংশন ইমপ্লিমেন্টেশনের ভিতরে ঢুকি:
ওহ ওয়াইট! এটি একদম ফেচের মতো দেখায় না! আমি বুঝতে পারছি না এই ফাংশনটি কী করতে চায়…
কল্পনা করুন কম্পোনেন্টের চারপাশে কিছু আছে, ধরা যাক একটি ফাইবার যা দেখায়:
কোডটি পড়ার জন্য কিছু সময় নিন।
এখন, customFetch ইমপ্লিমেন্টেশনে যাই:
পূর্বের স্নিপেটগুলোর গুরুত্বপূর্ণ অংশ হলো try/catch ব্লক।
চলুন এই বিভিন্ন কোড টুকরোর মাধ্যমে কী ঘটছে তা সারসংক্ষেপ করি:
Pokemonকম্পোনেন্টcustomFetchমেথডটি কল করে।customFetchমেথডটি তার অভ্যন্তরীণ ক্যাশ পড়তে চেষ্টা করে, কিন্তু সেটি খালি। তাই এটি কিছু থ্রো করে / কোথাও — বীজগাণিতিক প্রভাব।fiberপেরেন্ট সেই ইনফরমেশনটি ক্যাচ করে, হ্যান্ডেল করে, এবং ডেটা ফেচ করে। তারপরcustomFetchক্যাশকে ডেটা দিয়ে পূরণ করে।Component(args)-এ একটি রি-রেন্ডার ঘটে এবং এখনcustomFetchক্যাশটি পূর্ণ। ডেটা এখন কম্পোনেন্টে সিঙ্ক্রোনাস এপিআই ব্যবহার করে উপলব্ধ।
react-cache ইমপ্লিমেন্টেশন ডিটেইলস এবং বিভিন্ন থ্রো চেক করুন।
এই প্রক্রিয়ায় কিছু আপনার লক্ষ্য আকর্ষণ করতে পারে: render দুবার কল করা হয়েছে। একবার এরর থ্রো করার জন্য — কম্পোনেন্টটি পজ করছে — এবং একবার ডেটা পাওয়ার জন্য — কম্পোনেন্টটি রিজিউম করছে। রিয়েক্টের সাথে এটি ঠিক আছে একাধিক render কল ট্রিগার করা যেহেতু এটি শুধুমাত্র একটি পিউর ফাংশন — এর নিজস্ব কোনো সাইড ইফেক্ট নেই।
ওয়াইট… কী? render-এর কোনো সাইড ইফেক্ট নেই? ডোম (DOM) সম্পর্কে কী?
রিয়েক্ট ফেজ (React Phases)
আপনি যদি długoদিন রিয়েক্টের সাথে কাজ করে থাকেন, তবে আপনি শুনে থাকতে পারেন যে একাধিকবার রি-রেন্ডার করা ভালো অভ্যাস নয়। ফাইবার আর্কিটেকচারের আগে, প্রতিবার রেন্ডার ফাংশন কল করলে রিয়েক্ট কিছু অভ্যন্তরীণ কম্পিউটেশন করত এবং তারপর ডোম (DOM)-কে সংশোধন করত। উদাহরণস্বরূপ, এটি setState এর মাধ্যমে রেন্ডার ফাংশন কল করলে হত। প্রক্রিয়াটি ইনলাইন ছিল:
setState → render → ভার্চুয়াল নোডস তুলনা → ডোম নোডস আপডেট
ফাইবারের সাথে, প্রক্রিয়াটি কিছুটা আলাদা। এটি কিউ (queue) এবং ব্যাচ (batches) কনসেপ্ট চালু করেছে যা হাই-পারফরম্যান্স ডোম মডিফিকেশন অনুমতি দেয়।
ধারণা খুব সহজ। আমরা অনুমান করি স্ক্রিনগুলি সেকেন্ডে ~60 ফ্রেম চালাতে পারে। এই অনুমান থেকে, এবং উপলব্ধ জাভাস্ক্রিপ্ট ফাংশন ব্যবহার করে, কিছু কম্পিউটেশন এবং ডোম মডিফিকেশন প্রতি ~16.7ms-এ করা সম্ভব। ফাইবারের সাথে, রিয়েক্ট একাধিক মডিফিকেশন এনকিউ করতে পারে এবং সেকেন্ডে প্রায় 60বার সেগুলো কমিট করতে পারে।
এই ধরনের মডিফিকেশন রিয়েক্টকে তিনটি ফেজে বিভক্ত করতে সক্ষম করেছে যাদের নিজস্ব সুবিধা এবং বৈশিষ্ট্য রয়েছে:
_[ড্যান আব্রামোভ রিয়েক্ট ফেজের সম্পর্কে](https://twitter.com/dan_abramov/status/981712092611989509/photo/1?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E981712092611989509&ref_url=https%3A%2F%2Fmedium.com%2Fmedia%2Fbda1c34a16e9f8a8e3eb244716a1da72%3FpostId%3D2a57dc9c2e6d" rel="noopener" target="_blank" title=")
- রেন্ডার ফেজ পিউর এবং ডিটারমিনিস্টিক। এর কোনো সাইড ইফেক্ট নেই এবং এটিকে গঠনকারী বিভিন্ন ফাংশন একাধিকবার কল করা যেতে পারে। রেন্ডার ফেজ ইন্টারাপ্টিবল — এটি
renderফাংশন নয় যা পজ মোডে আছে, বরং পুরো ফেজটিই - প্রি-কমিট ফেজ আসল ডোম স্টেটে অ্যাক্সেস প্রদান করতে লক্ষ্য করে, যেমন স্ক্রোলবার পজিশন, রিড মোডে।
- কমিট ফেজ আসলে ডোমকে মডিফাই করে এবং ইন্টারাপ্টিবল নয়। রিয়েক্ট সেই ফেজে পজ করতে পারে না।
এই তিনটি ফেজের সেটটিই টাইম স্লাইসিং ক্যাপাবিলিটি চালু করেছে। রিয়েক্ট দুটি কম্পোনেন্ট ফাংশন কলের মাঝপথে রেন্ডার ফেজে পজ করতে পারে এবং প্রয়োজনে সেই ফেজটি রিজিউম করতে পারে।
ফাইবারে, render শুধুমাত্র একটি কম্পোনেন্টের সর্বশেষ উপলব্ধ রিপ্রেজেন্টেশন পাওয়ার লক্ষ্য করে তার অভ্যন্তরীণ স্টেটের ভিত্তিতে কিছু তুলনা করতে এবং জানতে যে রিয়েক্টকে ডোম পরিবর্তন করতে হবে কিনা। যদি একটি কমিট মডিফিকেশন প্রয়োজন হয়, তবে এটি মডিফিকেশনটিকে একটি "work in progress" কিউ-তে যোগ করবে।
রিয়েক্ট টিম রিয়েক্ট কনকারেন্ট (টাইম স্লাইসিং + সাসপেন্স) এবং ফাইবার আর্কিটেকচারের ধন্যবাদে বিশাল পারফরম্যান্স উন্নতি করেছেন। তারা ইভেন্ট প্রায়োরিটাইজেশন এবং কনকারেন্সি এর মতো বিভিন্ন ব্রাউজার সমস্যার বিরুদ্ধে ওয়ার্কঅরাউন্ড তৈরি করেছে।
যদি আমরা একটু পেছনে হটে দেখি, তবে কী আপনি দেখেছেন? প্রায়োরিটাইজেশন মনে হচ্ছে ব্রাউজার এবং ফ্রন্ট-এন্ড ফ্রেমওয়ার্কের জন্য নতুন চ্যালেঞ্জ।
অন্যান্য টিমও বর্তমান স্টেট-অফ-দ্য-আর্ট উন্নত করার এবং ভবিষ্যতের এপিআই প্রস্তাব করার জন্য কাজ করছে। গুগলের দৃষ্টিভঙ্গি:
নি:শুল্কে কোডিং শিখুন। freeCodeCamp-এর ওপেন সোর্স ক্যারিকুলাম ৪০,০০০ এরও বেশি মানুষকে ডেভেলপার হিসেবে नौকরি পেতে সাহায্য করেছে। শুরু করুন