استخدم async/await في مساراتك، وتعامل مع الأخطاء اللاتزامنية دون إسقاط الخادم.
افتح هذا الدرس في Kodokonلا تُرجِع مساراتك الحقيقية مصفوفات في الذاكرة: بل تقرأ الملفات، وتستعلم من قاعدة بيانات، وتستدعي واجهات برمجية أخرى. وكل هذه العمليات لاتزامنية. أنت تعرف async/await منذ مسار JavaScript؛ لنرَ كيفية استخدامها بنظافة في خادم. أول خبر سار: يمكن لدالة المسار أن تكون async.
import express from "express";
import { readFile } from "node:fs/promises";
const app = express();
app.get("/report", async (req, res) => {
const raw = await readFile("report.json", "utf8");
res.json(JSON.parse(raw));
});
app.listen(3000);يعمل هذا الكود... ما دام report.json موجودًا. فإذا فشلت القراءة، يُرفَض الوعد، وبحسب إصدار Express، يبقى الطلب دون رد أو يتسرب الخطأ إلى السجلات. والقاعدة المهنية: كل مسار لاتزامني يتعامل مع أخطائه، باستخدام try/catch وnext(error).
app.get("/report", async (req, res, next) => {
try {
const raw = await readFile("report.json", "utf8");
res.json(JSON.parse(raw));
} catch (error) {
next(error);
}
});تمرِّر next(error) الخطأ إلى معالِج الأخطاء المركزي. وهو برمجية وسيطة ذات أربعة وسائط، مُصرَّح بها بعد كل المسارات. مكان واحد لتسجيل الأخطاء وتنسيقها: هذا ما يميّز واجهة برمجية قابلة للصيانة عن مشروع عطلة نهاية أسبوع.
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({
error: "Internal server error"
});
});عادة أخيرة يجب اكتسابها: التوازي. عمليتان مستقلتان مربوطتان بـ await مرتين تُنفَّذان الواحدة تلو الأخرى. أما Promise.all فتطلقهما معًا: فيكون زمن الرد هو زمن الأبطأ، لا مجموع الاثنين.
async function fetchUsers() {
return [{ id: 1, name: "Ada" }];
}
async function fetchTasks() {
return [{ id: 1, title: "Review the code" }];
}
app.get("/dashboard", async (req, res, next) => {
try {
const [users, tasks] = await Promise.all([
fetchUsers(),
fetchTasks()
]);
res.json({ users, tasks });
} catch (error) {
next(error);
}
});async، ماذا تفعل بخطأ التقطته catch؟console.log والمتابعةnext(error) لتمريره إلى معالِج الأخطاءawait متتاليينPromise.allsetTimeout بينهماerr أولًاerrorHandler