এই কোর্সে আপনি ইতিমধ্যে বেশ কয়েকবার callback ব্যবহার করেছেন — fs.readFile()-এর শেষ আর্গুমেন্ট, on()-এ পাস করা প্রতিটি listener। এই পাঠটি প্যাটার্নটিকে স্পষ্ট করে আর সেই সমস্যার নাম দেয় যা promise-এ নিয়ে গিয়েছিল, যা পরে কভার করা হয়েছে।
একটি callback বিশেষ কিছু নয় — এটি শুধু অন্য একটি ফাংশনে আর্গুমেন্ট হিসেবে পাস করা একটি ফাংশন, সাথে সাথে না হয়ে পরে কল করার জন্য।
function processOrder(item, callback) {
console.log(`Processing order: ${item}`)
callback(item)
}
processOrder('Laptop Stand', (item) => {
console.log(`Done processing: ${item}`)
})Node-এর নিজস্ব বিল্ট-ইন async ফাংশনগুলো সবগুলো একটি প্রথা মেনে চলে: callback-এর প্রথম প্যারামিটার সবসময় একটি error (অথবা কিছু ভুল না হলে null), আর আসল ফলাফল এর পরে আসে।
fs.readFile('data.txt', 'utf8', (err, data) => {
if (err) {
console.error('Something went wrong:', err)
return
}
console.log(data)
})data স্পর্শ করার আগে প্রথমে err চেক করা, এটিই সেই প্রথা যা প্রতিটি Node callback মেনে চলে — চেকটি বাদ দিলে একটি ব্যর্থ read সুন্দরভাবে ব্যর্থ হওয়ার বদলে পরের লাইনে প্রোগ্রামটিকে ক্র্যাশ করায়।
একটি async ধাপ অন্যটিকে কল করলে তা দ্রুত nest হয়ে যায়:
fs.readFile('user.json', 'utf8', (err, userData) => {
if (err) return console.error(err)
fs.readFile('settings.json', 'utf8', (err, settingsData) => {
if (err) return console.error(err)
fs.readFile('preferences.json', 'utf8', (err, prefData) => {
if (err) return console.error(err)
console.log('All data loaded')
})
})
})তিন ধাপ গভীরে গিয়েই এটি অনুসরণ করা কঠিন হয়ে গেছে — প্রতিটি ধাপ শেষটির ভেতরে ইনডেন্ট করা, error হ্যান্ডলিং প্রতিটি স্তরে পুনরাবৃত্তি হয়, আর চতুর্থ একটি ধাপ যোগ করার অর্থ আরও গভীরে nest করা। এই আকৃতিটি নিজস্ব একটি ডাকনাম অর্জন করেছে: callback hell। এটি স্কেলের সাথে ভালো হয় না; এটি আরও খারাপ হয়।
এটিই ঠিক সেই সমস্যা যা সমাধান করতে Promise আবিষ্কার হয়েছিল — এই পিরামিডটিকে আবার এমন কিছুতে সমতল করা যা উপর থেকে নিচে পড়া যায়। পরের পাঠ ঠিক এখান থেকে শুরু হয়।