জাভাস্ক্রিপ্ট টিউটোরিয়াল-শিখুন গল্পে গল্পে সাথে 1100+ Exercise

  • জাভাস্ক্রিপ্ট পরিচিতি-Introduction to JavaScript
  • প্রোগ্রামিং শুরু করতে কতটুকু গণিত লাগে?
  • প্রোগ্রামিং শুরু করতে কতটুকু ইংরেজি জানা লাগে?
  • ভালো প্রোগ্রামার কিভাবে হবো? [+৭টি গুরুত্বপূর্ণ টিপস]
  • তিন লেয়ারের JSON শাসন
  • Promise রক্ষাকারী প্রেমিক
  • fetch-এর প্যাঁচ
  • ক্র্যাশ খাইছে CRUD
  • try করে catch কর
  • Async আর Await-এর ভাজা মাছ

Async আর Await-এর ভাজা মাছ


কিছু কিছু পোলাপান আছে, এমন একটা ভাব ধরে রাখে যে, ভাজা মাছ উল্টিয়ে খেতে পারে না। অথচ ভিতরে ভিতরে ভাজা মাছ, কাটাকুটা সব খেয়ে হজম করে বসে থাকে।


জাভাস্ক্রিপ্টও ওপরে ওপরে এমন ভাব করে যে, সে সিঙ্গেল থ্রেডে চলে। কিন্তু ভিতরে ভিতরে সে Asynchronous কোড ঠিকই হ্যান্ডেল করে ফেলে। আবার Asynchronous কোড হ্যান্ডেল করার পাশাপাশি async এবং await দিয়ে এমনভাবে কোড লেখার সিস্টেম নিয়ে আসছে, যাতে দেখলে মনে হয় নরমাল synchronous কোড। আসলে কিন্তু Asynchronous কোড। 


আর আসল কথা হচ্ছে, এই async আর await ইউজ করলে কোড দেখা ও পড়া অনেক সহজ হয়ে ওঠে। 


async কী?

async কি-ওয়ার্ডটি একটি ফাংশনকে asynchronous ফাংশনে রূপান্তরিত করে। এই async ফাংশন Promise রিটার্ন করে। ফাংশন লেখার সময় function কি-ওয়ার্ডের আগে মাস্ট async লিখতে হবে। আর অ্যারো ফাংশন হলে প্যারামিটারের আগে async লিখতে হবে। async না লিখেলে ফাংশনের ভিতরে await ইউজ করা যাবে না।


  async function fetchData() { }
  const fetchUserData = async () => { }


await কী?

শুধু async ফাংশনের মধ্যে await কি-ওয়ার্ডটি ব্যবহার করা যায়। যখন await একটি Promise দেখবে, তখন এটি সেই Promise শেষ হওয়ার জন্য অপেক্ষা করবে এবং তারপর প্রমিজের ফলাফল রিটার্ন করবে।


প্রথমে একটা সিম্পল উদারহণ দিয়ে fetch-এর পর then-এর ভিতরে কলব্যাক ফাংশন দিয়ে ডাটা লোড করে ফেলি। 


  fetch('https://jsonplaceholder.typicode.com/users/1')
   .then(response => response.json())
   .then(data => {
    console.log(data);
   })
   .catch(error => {
    console.error('Error:', error);
   });


async await 

এখন যদি ওপরের fetch-কে async await-সহ ইউজ করি, তাহলে দেখতে নিচের মতো হবে। প্রথমে function কি-ওয়ার্ডের আগে async মাস্ট লিখতে হবে। তারপর একটা ফাংশন লিখবি নরমালভাবে। আর await সাধারণত try-catch-এর ভিতরে লেখা হয়, যাতে কোনো এরর খেলে সেটা catch ব্লক দিয়ে ক্যাচ করে হ্যান্ডেল করা যায়। 


এরপর প্রথম লাইনে একটা url, তারপরের লাইনে একটা ভেরিয়েবল response, সেটার ডানপাশে await করতেছে। একটা fetch থেকে রেসপন্স রিটার্ন করার জন্য। নরমাল fetch ইউজ করলে এইটা then-এর ভিতরে পাওয়া যেত। এইখানে async await করার কারণে সরাসরি ভেরিয়েবলে পেয়ে যাচ্ছস। জিনিসটা কিন্তু সিম্পল। async চিন্তা করা লাগতেছে না। কলব্যাকের চিন্তা করা লাগতেছে না। জাস্ট fetch কলের আগে একটা await দিয়েই জিনিসটা সিম্পল করে ফেলছে। 


তারপরের লাইনে আরেকটা ভেরিয়েবল। যেটার নাম data, আর সেটার ডানপাশে await আছে। অর্থাৎ অপেক্ষা করতেছে। response.json() ফিনিশ করার জন্য। যাতে ডাটাকে json দিয়ে জাভাস্ক্রিপ্ট অবজেক্টে কনভার্ট করতে পারে। 


এতেই সিম্পলভাবে ডাটা পেয়ে যাবে। তারপর ডাটা দিয়ে ওয়েবসাইটে দেখানোর কাজ সহজেই করে ফেলতে পারে।


আর যদি কোডে কোনো এরর খায়, সেটা ধরার জন্য fetch কলের মেইন বিষয়টা try ব্লকের মধ্যে রাখছি। আর এরর খেলে সেটা catch ব্লকের ভিতরে হ্যান্ডেল করে ফেলব। 


আর ওভারঅল fetch-এর বিষয়টা যেহেতু একটা ফাংশনের ভিতরে। তাই এই fetch কাজ করার জন্য আমাদের ফাংশনকে কল করে দিতে হবে। নচেৎ ডাটা কিন্তু লোড হবে না। 


  async function fetchData() {
   try {
    const url = 'https://jsonplaceholder.typicode.com/users/1';
    const response = await fetch(url);
    const data = await response.json();
    console.log(data);
   } 
   catch (error) {
    console.error('Error:', error);
   }
  }

  fetchData();


ওপরে নরমাল একটা ফাংশনের মধ্যে আমরা async await ইউজ করছিলাম। যদি অ্যারো ফাংশনের মধ্যে async await ইউজ করতে যাস, সেইম সিস্টেম। জাস্ট async কি-ওয়ার্ডটা অ্যারো ফাংশনের প্যারামিটারের আগে লিখতে হবে। এইটুক খেয়াল করলেই হবে। 


  const fetchUserData = async () => {
   try {
    const response = await fetch('https://jsonplaceholder.typicode.com/users/1');
    const data = await response.json();
    console.log(data);
   } catch (error) {
    console.error('Error:', error);
   }
  };

  fetchUserData();


একটু আগের নরলাম fetch আর এই async await কিন্তু একজাক্ট সেইম কাজই করে। নরমাল fetch আর কলব্যাক ফাংশন ইউজ করার কারণে কোড একটু প্যাঁচাপেঁচি লাগতে পারে। আর async-await ইউজ করে কোড লিখলে কোড অনেক গুছানো ফিল দেয়। 


Callback hell 

একটার পর একটা অ্যাসিনক্রোনাস কাজ করতে গেলে একটার ভিতরে একটা কলব্যাক ফাংশন লিখতে হয়। তখন দেখতে জিনিসটা সাইড থেকে পিরামিডের মতো হয় এবং এই রকম কোড পড়া, বুঝা, এডিট করা, ম্যানেজ করা অনেক কঠিন হয়ে যায়। তখন এইটাকে বলে কলব্যাক হেল। সেই রকম একটা উদাহরণ দেখে ফেল। 


কাহিনি এমন হচ্ছে, প্রথমে ইউজারের ডাটা লোড করবে। ইউজার পেলে সেই ইউজারের আইডি দিয়ে তার সব পোস্টের ডাটা লোড করবে। তারপর তার সব পোস্ট পেলে প্রথম পোস্টের comments-এর ডাটা লোড করবে কমেন্ট আইডি দিয়ে। এইভাবে একটা পর একটা কলব্যাক দিয়ে দিয়ে ডাটা লোড করতে গেলে একটা কলব্যাক হেল হয়ে দাঁড়ায়। 


  // sample pseudo code. Will not run properly
  fetch('user-url', (user) => {
    user.json((user) => {
      fetch(`post-url?userId=${user.id}`, (post) => {
        post.json((posts) => {
          fetch(`c-url?postId=${posts[0].id}`, (cmnts) => {
            comments.json((cmnts) => {
               // Do something with likes
            });
          });
        });
      });
    });
  });


callback hell-এর আরেকটা নাম আছে, যেটাকে বলে Pyramid of Doom। কারণ, এইটা সাইড থেকে দেখলে মিশরের পিরামিডের মতো দেখতে। আর লজিক্যালভাবে দেখলে, দেখা যায় একটার ভিতরে আরেকটা, তার ভিতরের আরেকটা, এইরকম চলতেই আছে। এই রকম লেয়ার বাই লেয়ারের ভিতরে যাওয়াটাকে deep nesting কেউ কেউ বলে। এইসব ক্ষেত্রে কোনো সমস্যা হলে জীবন তেজপাতা হয়ে যায়। সমস্যা খুঁজে বের করা বা কোড ডিবাগ করা অনেক প্যারাময় হয়ে দাঁড়ায়। তখন async await ইউজ করলে কোড দেখতে, পড়তে, বুঝতে, এডিট করতে অনেক সহজ হয়ে দাঁড়ায়। 


  async function fetchData() {
   try {
    const userRes = await fetch('user-url');
    const user = await userRes.json();
   
    const postRes = await fetch(`post-url?userId=${user.id}`);
    const posts = await postRes.json();
   
    const cmntsRes = await fetch(`c-url?postId=${posts[0].id}`);
    const cmnts = await cmntsRes.json();
   
    // Do something with likes
   } catch (error) {
    console.error('Error:', error);
   }
  }

  fetchData();


এইবার বুঝতে পারছস। async await কাজ সেইম করে। কিন্তু কোডের সৌন্দর্য বাড়িয়ে দেয়। 


Practice: 

  1. async-await কেন ব্যবহার করা হয়?
  2. একটি async ফাংশন লিখে ফেল, আর এইটার নাম দিবি fetchUser। এই ফাংশনের ভিতরে এই url লিংক 'https://jsonplaceholder.typicode.com/users/2' থেকে ডাটা লোড করে ডাটাকে console লগ করবি। এ ছাড়া অবশ্যই try-catch ইউজ করবি। 
  3. Callback hell বা Pyramid of Doom কী জিনিস? এইটা কখন হয়, আর এর সমাধান কী?
  4. 'https://jsonplaceholder.typicode.com/posts?userId=1' থেকে তার সব পোস্ট লোড কর। দুইভাবে কর। প্রথমবার callback স্টাইলে আর পরেরবার async-await দিয়ে।
  5. async-await দিয়ে একটা ফাংশন লিখ, যা 'https://jsonplaceholder.typicode.com/comments' থেকে কমেন্ট লোড করবে। অবশ্যই try-catch-finally ইউজ করবি এবং finally-তে একটা console.log দে, 'Request completed!'.।
  6. Async-await দিয়ে এমন একটা ফাংশন লিখ, যেটা ইউজার ID প্যারামিটার হিসেবে নিবে। তারপর 'https://jsonplaceholder.typicode.com/users/ID' থেকে সেই ইউজারের ডাটা লোড করবে। ইউআরএলের মধ্যে লাস্টে টেমপ্লেট স্ট্রিং দিয়ে প্যারামিটার হিসেবে যেই ID দিবি, সেটা ডায়নামিকভাবে বসিয়ে দিবি। কোনো এরর হলে সেটাকে try-catch দিয়ে হ্যান্ডল করবি।


Previous PageNext Chapter