مقدمة سريعة: ليش نحتاج async/await؟
زمان، لما كنا نتعامل مع عمليات بتاخد وقت (زي جلب بيانات من سيرفر أو قراءة ملف)، كنا نستخدم Callbacks أو Promises. الكولباكس كانت بتخلي الكود معقد (Callback Hell)، والـ Promises حلت جزء كبير من المشكلة بس لسه ممكن الكود يكون صعب القراءة شوية مع سلاسل .then().then(). هنا بيجي دور async و await عشان يخلوا الكود اللي بيتعامل مع الـ Promises يبان كأنه synchronous (متزامن) وسهل القراءة.
ايش يعني async؟
لما تحط كلمة async قبل أي دالة (Function)، ده بيخليها دالة غير متزامنة. ببساطة، أي دالة async دايمًا بترجع Promise. حتى لو رجعت قيمة عادية، JavaScript هتحولها لـ Promise تم حلها (resolved Promise).
async function myFunction() {
return "Hello Async!";
}
myFunction().then(value => console.log(value)); // Output: Hello Async!
async function anotherFunction() {
return Promise.resolve("Another Hello!");
}
anotherFunction().then(value => console.log(value)); // Output: Another Hello!
ايش يعني await؟
الـ await كلمة سحرية! تقدر تستخدمها بس داخل الدالة اللي عليها علامة async. وظيفتها إنها "توقف" تنفيذ الكود داخل الدالة async لحد ما الـ Promise اللي أنت بتعملها await عليها تخلص (تتحل أو تترفض). بمجرد ما الـ Promise تخلص، الـ await بترجع القيمة اللي حلت بيها الـ Promise.
ملاحظة مهمة: الـ
awaitبتوقف تنفيذ الدالة اللي هي فيها بس، مش بتوقف البرنامج كله (Main Thread). ده بيخلي الـ UI بتاعك ما يعلقش.
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function greet() {
console.log("Start greeting...");
await delay(2000); // استنى ثانيتين
console.log("Hello after 2 seconds!");
}
greet();
console.log("This message appears immediately, while greet() is waiting.");
مثال عملي: جلب بيانات من API
تخيل إنك عايز تجيب بيانات من API خارجي. باستخدام async/await الموضوع بيكون سلس جدًا:
async function fetchData() {
try {
console.log("Fetching data...");
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1'); // استنى لحد ما الـ fetch يخلص
const data = await response.json(); // استنى لحد ما الـ response تتحول لـ JSON
console.log("Data fetched successfully:", data);
} catch (error) {
console.error("Error fetching data:", error);
}
}
fetchData();
التعامل مع الأخطاء (Error Handling)
لو الـ Promise اللي عملت عليها await اترفضت (rejected)، الـ await هترمي استثناء (throw an error). عشان تتعامل مع الأخطاء دي، بنستخدم try...catch زي أي كود عادي.
async function getBadData() {
try {
const response = await fetch('https://nonexistent-url.com/data'); // هيحصل خطأ هنا
const data = await response.json();
console.log(data);
} catch (error) {
console.error("Oops! Something went wrong:", error.message);
}
}
getBadData();
تنفيذ مهام متعددة بالتوازي (Parallel Execution)
لو عندك كذا Promise عايز تنفذهم في نفس الوقت (مش ورا بعض)، ما تستخدمش await على كل واحدة لوحدها بشكل متسلسل، لأن ده هيخلي كل واحدة تستنى اللي قبلها. الأفضل تستخدم Promise.all():
async function fetchMultipleData() {
console.log("Fetching multiple data sources in parallel...");
try {
const [usersResponse, postsResponse] = await Promise.all([
fetch('https://jsonplaceholder.typicode.com/users/1'),
fetch('https://jsonplaceholder.typicode.com/posts/1')
]);
const user = await usersResponse.json();
const post = await postsResponse.json();
console.log("User:", user);
console.log("Post:", post);
} catch (error) {
console.error("Error fetching multiple data:", error);
}
}
fetchMultipleData();
نصيحة: استخدم
Promise.allSettled()لو عايز كل الـ Promises تخلص سواء نجحت أو فشلت، وتشوف نتائج كل واحدة على حدة، بدل ماPromise.all()توقف كل حاجة لو واحدة بس فشلت.
خلاصة الكلام
async و await خلوا التعامل مع الكود غير المتزامن في JavaScript أسهل وأوضح بكتير. بيخلوا الكود اللي بيعتمد على الـ Promises يبان زي الكود المتزامن العادي، وده بيحسن من قابلية القراءة والصيانة. استخدمهم دايمًا لما تتعامل مع الـ Promises عشان تكتب كود أنظف وأسهل للفهم.