8.10. Promises এবং async/await

 

প্রমিজ:

জাভাস্ক্রিপ্ট এর অ্যাসিনক্রোনাস আচরণ সম্পর্কে আমরা জানি। প্রমিসের কাজ হচ্ছে এ ধরনের অ্যাসিনক্রোনাস অপারেশনকে হ্যান্ডল করা। এখন আমরা রিমোট একটা সার্ভারের উপর অপারেশন চালাচ্ছি, কিন্তু ডাটা না আসা পর্যন্ত কিন্তু আমরা বলতে পারি না সে অপারেশন সফল হবে না বিফলে যাবে। আর মূলত এইসব হ্যান্ডল করার জন্যেই প্রমিস কাজ করে। আমাদের বেশিরভাগ ক্ষেত্রেই প্রমিস হ্যান্ডেল করতে হয়। প্রমিসের সিনট্যাক্স অনেকটা এইরকম হয়ে থাকেঃ

let myPromise = new Promise(function(myResolve, myReject) {
// "Producing Code" (May take some time)

  myResolve(); // when successful
  myReject();  // when error
});

// "Consuming Code" (Must wait for a fulfilled Promise)

myPromise.then(
  function(value) { /* code if successful */ },
  function(error) { /* code if some error */ }
);

যখনি Producing কোড ফলাফল পেয়ে যায়, এইটা তখন নিচের দুইটা কলব্যাক থেকে একটাকে কল করে।

ফলাফল কল
Success myResolve(result value)
Error myReject(error object)

এখন প্রমিস অবজেক্ট আবার ৩ ধরণের হতে পারে, যেমনঃ 

  • Pending
  • Fulfilled
  • Rejected

Pending অবস্থায় ফলাফল undefined, Fulfilled অবস্থায় ফলাফল একটি ভ্যালু, এবং Rejected অবস্থায় ফলাফল একটি error অবজেক্ট।

নিচের মতো করে প্রমিস ব্যবহার করতে হয়ঃ 

myPromise.then(
  function(value) { /* code if successful */ },
  function(error) { /* code if some error */ }
);

 

async এবং await:

async এবং await প্রমিস লিখতে খুবই সহজ করে। async একটি ফাংশন দিয়ে প্রমিস রিটার্ন করে এবং await একটি ফাংশনকে প্রমিসের জন্য অপেক্ষা করায়। একটা প্রমিস হ্যান্ডেল করার পর এটার ভিতরে কলব্যাক ফাংশন কল করতে হয়। আবার সেই কলব্যাক ফাংশনের ভিতরে প্রমিস থেকে আসা ডাটাগুলো অ্যাক্সেস করতে হয়। এভাবে একটার পর একটার ভিতরে গিয়ে গিয়ে এভাবে আমাদের অপারেশনগুলো চালাতে হয় শুধুমাত্র জাভাস্ক্রিপ্ট এর অ্যাসিনক্রোনাস আচরণের কারণে।

জাভস্ক্রিপ্ট-এ মূলত প্রমিস হ্যান্ডেলের জন্যই async আর await এর পরিচয় করিয়ে দেওয়া হয়েছে। যেখানেই আপনি এরকম অ্যাসিনক্রোনাস কোডকে সিনক্রোনাস আচরণ করাতে চান সেখানেই এগুলো ব্যবহার করতে পারবেন। তবে এখানে কিছু নিয়ম কানুন আছে। আপনাকে async এই কীওয়ার্ডটা ব্যবহার করতে হবে ফাংশনের সাথে। আপনি যে কোডগুলোকে সিনক্রোনাস আচরণ করাতে চাচ্ছেন সেগুলো সবগুলো একটা ফাংশনের ভিতরে ঢুকিয়ে সেই ফাংশনের নামের আগে জাস্ট এভাবে async কীওয়ার্ডটা লাগিয়ে দিবেনঃ

const promiseHandle = async() => {
   const data = await myPromise;
   console.log(data);
}

এখানে দেখুন লক্ষ্য করে আমি ঠিক এর পরের লাইনেই আমাদের প্রমিস থেকে আসা ডাটা প্রিন্ট করে দিয়েছি। হ্যা এখানেই async আর await এর ম্যাজিক। এটা আমাদের অ্যাসিনক্রোনাস কোডকে সিনক্রোনাস আচরণ করতে সাহায্য করে যাতে আমাদের আর কলব্যাকে হেলে পড়তে না হয়। আমরা একদম লাইন বাই লাইন ইন্সট্রাকশন দিয়েই ডাটা উদ্ধার করতে পারবো।

এখন যদি প্রমিস রিজেক্টেড হয় তাহলে? হ্যা তাহলে আমরা  try catch ব্লক দিয়েই আমরা আমাদের এই এরর হ্যান্ডল করতে পারবো। 

 
উদাহরন
  • নিচের উদাহরণটি লক্ষ করি:

async function f() {
  return 1;
}

f().then(alert); // 1
  • আমরা চাইলে উপরের কোডটি এভাবেও লিখতে পারি:

async function f() {
  return Promise.resolve(1);
}
f().then(alert); //1
  • আমরা চাইলে resolve() বা reject() থেকে ডাটা পাঠাতে পারিঃ

const aPromiseWithData = control => { 
   return new Promise((resolve, reject) => {
      setTimeout(() => {
         if(control) {
            resolve('Simple Success Data');
         } else {
            reject('Simple Error Data');
         }
      }, 3000)
   })
}
  • এখানে resolve() বা reject() থেকে ঠিক যেভাবে ডাটাগুলো পাঠানো হয়েছে সেভাবেই আমরা .then() বা .catch() এর কলব্যাক থেকে অ্যাক্সেস করতে পারবো আর্গুমেন্ট হিসেবে অ্যাক্সেপ্ট করেঃ

aPromiseWithData(true)
  .then((data) => {
     console.log(data);
  })
  • কোনো কোনো সময় আমাদের একাধিক প্রমসিও হ্যান্ডল করতে হতে পারে। তারপর .then() দিয়ে কলব্যাক কল করতে পারবো যেটা এই দুইটা প্রমিস কমপ্লিট হলে পরেই রান করবে। আর এই প্রমিসগুলো থেকে আসা ডাটাগুলো এই কলব্যাক ফাংশনে অ্যারে আকারে আসবেঃ
const promise1 = new Promise((resolve, reject) => {
   setTimeout(() => {
      if(true) {
         resolve('Promise 1 Resolved');
      } else {
         reject('Promise 1 Error');
      }
   }, 5000)
 })

const promise2 = new Promise((resolve, reject) => {
   setTimeout(() => {
      if(true) {
         resolve('Promise 2 Resolved');
      } else {
         reject('Promise 2 Error');
      }
   }, 5000)
})

Promise.all([promise1, promise2]);
Promise.all([promise1, promise2]).then((dataArr) => { console.log(dataArr); })

 

এসো নিজে করি
  • নিচের কোড স্নিপেটের আউটপুট কি হবে?

firstPromise = new Promise((resolve) => {
    resolve("First promise.")
});
secondPromise = new Promise((resolve) => {
    resolve("Second promise.")
});
console.log("First console.")
setTimeout(() => console.log("First setTimeout."), 1000);
setTimeout(() => console.log("Second setTimeout."));
firstPromise.then(response => console.log(response));
secondPromise.then(response => console.log(response));
  • নিচের কোড স্নিপেটের আউটপুট কি হবে?
function myDisplayer(some) {
  document.getElementById("demo").innerHTML = some;
}

let myPromise = new Promise(function(myResolve, myReject) {
  let x = 0;

  if (x == 0) {
    myResolve("OK");
  } else {
    myReject("Error");
  }
});

myPromise.then(
  function(value) {myDisplayer(value);},
  function(error) {myDisplayer(error);}
);
  • নিচের কোড স্নিপেটের আউটপুট কি হবে?
let done = true

const isItDoneYet = new Promise((resolve, reject) => {
  if (done) {
    const workDone = 'Here is the thing I built'
    resolve(workDone)
  } else {
    const why = 'Still working on something else'
    reject(why)
  }
})

const checkIfItsDone = () => {
  isItDoneYet
    .then(ok => {
      console.log(ok)
    })
    .catch(err => {
      console.error(err)
    })
}

checkIfItsDone()
  • নিচের কোড স্নিপেটের আউটপুট কি হবে?
const p = new Promise((res, rej) => {
  res(1);
})

async function asyncReturn() {
  return p;
}

function basicReturn() {
  return Promise.resolve(p);
}

console.log(p === basicReturn());
console.log(p === asyncReturn());
  • নিচের কোড স্নিপেটের আউটপুট কি হবে?
function asynchronous_operational_method() {
  let first_promise = new Promise((resolve, reject) => resolve("Hello"));
  let second_promise = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(" Vivasoft..”);
    }, 1000);
  });
  let combined_promise = Promise.all([first_promise, second_promise]);
  return combined_promise;
}
 
async function display() {
  let data = await asynchronous_operational_method();
  console.log(data);
}
 
display();