گاهی کد async/await خیلی شلوغ میشه چون پر از try/catch تکراریه. یه الگوی جمعوجور میتونه هم کد رو تمیز کنه، هم مدیریت خطاها رو واضحتر کنه.
ایده اینه: بهجای try/catch دور هر await، یه helper کوچک مینویسیم که همیشه نتیجه رو به شکل یک آرایه برگردونه: [err, data]. شبیه سبک Node.js، ولی مدرن و تمیز 😎
نکات مهم ✅
• ساختار کنترل خطا توی تابع مشخص و خطی میمونه، بدون چندین try/catch تو در تو.
• میشه این الگو رو برای هر Promise (مثل عملیات دیتابیس، fetch، کار با فایل در Node.js و ...) دوباره استفاده کرد.
• حواست باشه همیشه یا هر دو مقدار [err, data] رو destructure کنی، یا حداقل err رو چک کنی تا Memory Leak یا رفتار غیرمنتظره نگیری.
برای ساخت API تمیز و قابل تست، این الگو کنار TypeScript یا JSDoc خیلی خوب جواب میده، چون نوع خروجی همیشه قابل پیشبینی و یکنواخته.
امتحان این pattern روی فانکشنهای async کوچیک شروع میشه، بعد کمکم میتونه تبدیل بشه به style اصلیت برای هندل کردن Promiseها 🙌
مرجع بیشتر درباره Promise و خطاها تو MDN:
MDN - Promise
🔖 #Javascript #JS #جاوااسکریپت #JavaScript #async_await #Promise #error_handling #ES6
👤 Developix
💎 Channel: @DevelopixJavascript
ایده اینه: بهجای try/catch دور هر await، یه helper کوچک مینویسیم که همیشه نتیجه رو به شکل یک آرایه برگردونه: [err, data]. شبیه سبک Node.js، ولی مدرن و تمیز 😎
const to = (promise) => promise
.then((data) => [null, data])
.catch((err) => [err, null]);
async function fetchUser(userId) {
const [err, res] = await to(
fetch(`https://api.example.com/users/${userId}`)
);
if (err) {
console.error('خطا در درخواست:', err);
return null;
}
const [parseErr, data] = await to(res.json());
if (parseErr) {
console.error('خطا در parse کردن JSON:', parseErr);
return null;
}
return data;
}
نکات مهم ✅
• ساختار کنترل خطا توی تابع مشخص و خطی میمونه، بدون چندین try/catch تو در تو.
• میشه این الگو رو برای هر Promise (مثل عملیات دیتابیس، fetch، کار با فایل در Node.js و ...) دوباره استفاده کرد.
• حواست باشه همیشه یا هر دو مقدار [err, data] رو destructure کنی، یا حداقل err رو چک کنی تا Memory Leak یا رفتار غیرمنتظره نگیری.
برای ساخت API تمیز و قابل تست، این الگو کنار TypeScript یا JSDoc خیلی خوب جواب میده، چون نوع خروجی همیشه قابل پیشبینی و یکنواخته.
امتحان این pattern روی فانکشنهای async کوچیک شروع میشه، بعد کمکم میتونه تبدیل بشه به style اصلیت برای هندل کردن Promiseها 🙌
مرجع بیشتر درباره Promise و خطاها تو MDN:
MDN - Promise
🔖 #Javascript #JS #جاوااسکریپت #JavaScript #async_await #Promise #error_handling #ES6
👤 Developix
💎 Channel: @DevelopixJavascript
❤7👎2🔥1
در کد زیر توسعهدهنده میخواهد یک حلقه از توابع async بسازد که بهترتیب و با فاصله زمانی اجرا شوند، اما نتیجهی نهایی آرایهای خالی یا ناقص برمیگردد و همهی async ها درست منتظر نمیمانند.
سوال: در این کد چه چیزی باید اصلاح شود تا Promise chain بهدرستی کار کند و همهی درخواستهای async بهترتیب انجام شده و در نهایت آرایه
🔖 #Javascript #JS #جاوااسکریپت
👤 Developix
💎 Channel: @DevelopixJavascript
سوال: در این کد چه چیزی باید اصلاح شود تا Promise chain بهدرستی کار کند و همهی درخواستهای async بهترتیب انجام شده و در نهایت آرایه
results بعد از تکمیل همهی عملیات برگردانده شود؟function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function fetchData(id) {
await delay(100);
console.log("fetched", id);
return { id, time: Date.now() };
}
function runSequential(ids) {
const results = [];
ids.forEach(async (id) => {
const data = await fetchData(id);
results.push(data);
});
return Promise.resolve(results);
}
runSequential([1, 2, 3]).then(console.log);
🔖 #Javascript #JS #جاوااسکریپت
👤 Developix
💎 Channel: @DevelopixJavascript
❤2
در کد زیر یک خطای ظریف در استفاده از async/await و Array.prototype.map وجود دارد که باعث میشود رفتار برنامه مطابق انتظار نباشد.
چه چیزی باید در این کد تغییر کند تا همه درخواستها به صورت async درست اجرا شوند و مقدار نهایی
🔖 #Javascript #JS #جاوااسکریپت
👤 Developix
💎 Channel: @DevelopixJavascript
چه چیزی باید در این کد تغییر کند تا همه درخواستها به صورت async درست اجرا شوند و مقدار نهایی
results به درستی شامل پاسخهای resolve شده باشد؟const urls = [
"https://api.example.com/user/1",
"https://api.example.com/user/2",
"https://api.example.com/user/3",
];
async function fetchUsers() {
let results = [];
urls.map(async (url) => {
const res = await fetch(url);
const data = await res.json();
results.push(data);
});
return results;
}
fetchUsers().then((users) => {
console.log("Users:", users);
});
🔖 #Javascript #JS #جاوااسکریپت
👤 Developix
💎 Channel: @DevelopixJavascript
❤6
قانون «یک سطح انتزاع در هر تابع» در JavaScript 🧠✨
یکی از نکات طلایی در Clean Code این است که هر تابع فقط با یک سطح انتزاع کار کند. یعنی یا درگیر جزئیات low-level باشد، یا فقط کارهای high-level را صدا بزند؛ نه هر دو را قاطی.
این قانون کمک میکند:
• خوانایی کد بالا برود 👀
• Refactor کردن سادهتر شود 🔧
• تستنویسی راحتتر شود ✅
🍂 یک مثال از کد شلوغ در Node.js / Express
این تابع هم validation انجام میدهد، هم کار دیتابیس، هم جزئیات hash، هم پاسخ HTTP. سطحهای انتزاع قاطی شدهاند.
🌱 Refactor با یک سطح انتزاع در هر تابع
حالا:
• تابع
• تابع
• route handler فقط orchestration انجام میدهد ✅
این جداسازی باعث میشود بعداً راحتتر TypeScript اضافه کنید، Unit Test بنویسید، یا منطق ساخت کاربر را در سرویس دیگری (مثلاً در یک worker) استفاده کنید.
منابع برای مطالعه بیشتر:
• Refactoring.Guru
• MDN – Learn JS
قدمبهقدم همین الگو را روی قسمتهای شلوغ پروژههای Node.js / React / Next.js خود پیاده کنید؛ هر بار که یک تابع را به یک سطح انتزاع محدود میکنید، کدتان قابلاعتمادتر و نگهداریپذیرتر میشود 🚀
🔖 #Javascript #JS #جاوااسکریپت #Clean_Code #JavaScript #Node_js #Express #Refactoring #Best_Practices
👤 Developix
💎 Channel: @DevelopixJavascript
یکی از نکات طلایی در Clean Code این است که هر تابع فقط با یک سطح انتزاع کار کند. یعنی یا درگیر جزئیات low-level باشد، یا فقط کارهای high-level را صدا بزند؛ نه هر دو را قاطی.
این قانون کمک میکند:
• خوانایی کد بالا برود 👀
• Refactor کردن سادهتر شود 🔧
• تستنویسی راحتتر شود ✅
🍂 یک مثال از کد شلوغ در Node.js / Express
app.post('/api/users', async (req, res) => {
const { email, password } = req.body;
if (!email || !password) {
return res.status(400).json({ message: 'Invalid data' });
}
if (!email.includes('@')) {
return res.status(400).json({ message: 'Invalid email' });
}
const exists = await db.collection('users').findOne({ email });
if (exists) {
return res.status(409).json({ message: 'Already exists' });
}
const hash = await bcrypt.hash(password, 10);
const user = {
email,
password: hash,
createdAt: new Date()
};
await db.collection('users').insertOne(user);
res.status(201).json({ id: user._id, email: user.email });
});این تابع هم validation انجام میدهد، هم کار دیتابیس، هم جزئیات hash، هم پاسخ HTTP. سطحهای انتزاع قاطی شدهاند.
🌱 Refactor با یک سطح انتزاع در هر تابع
const validateUserPayload = (body) => {
const { email, password } = body;
if (!email || !password) return 'Invalid data';
if (!email.includes('@')) return 'Invalid email';
return null;
};
const createUser = async ({ email, password }, db, hasher) => {
const exists = await db.collection('users').findOne({ email });
if (exists) return { error: 'Already exists' };
const passwordHash = await hasher(password);
const user = {
email,
password: passwordHash,
createdAt: new Date()
};
const result = await db.collection('users').insertOne(user);
return { id: result.insertedId, email: user.email };
};
app.post('/api/users', async (req, res) => {
const validationError = validateUserPayload(req.body);
if (validationError) {
return res.status(400).json({ message: validationError });
}
const result = await createUser(
req.body,
db,
(password) => bcrypt.hash(password, 10)
);
if (result.error) {
return res.status(409).json({ message: result.error });
}
res.status(201).json(result);
});حالا:
• تابع
validateUserPayload فقط validation است ✅• تابع
createUser فقط منطق ساخت کاربر را دارد ✅• route handler فقط orchestration انجام میدهد ✅
این جداسازی باعث میشود بعداً راحتتر TypeScript اضافه کنید، Unit Test بنویسید، یا منطق ساخت کاربر را در سرویس دیگری (مثلاً در یک worker) استفاده کنید.
منابع برای مطالعه بیشتر:
• Refactoring.Guru
• MDN – Learn JS
قدمبهقدم همین الگو را روی قسمتهای شلوغ پروژههای Node.js / React / Next.js خود پیاده کنید؛ هر بار که یک تابع را به یک سطح انتزاع محدود میکنید، کدتان قابلاعتمادتر و نگهداریپذیرتر میشود 🚀
🔖 #Javascript #JS #جاوااسکریپت #Clean_Code #JavaScript #Node_js #Express #Refactoring #Best_Practices
👤 Developix
💎 Channel: @DevelopixJavascript
👍4❤3👎3
✨ ساخت یک Todo List ساده با JavaScript خالص (بدون Framework)
خیلی وقتها برای تمرین JavaScript و DOM، یک پروژه کوچیک و واقعی مثل Todo List بهترین گزینهست. هم رویدادها رو لمس میکنی، هم کار با DOM و هم مدیریت state ساده رو.
یکی از بهترین رفرنسها برای کار با DOM و رویدادها، مستندات MDN هست:
MDN DOM Introduction
در این تمرین، با چند مفهوم مهم سر و کار داریم:
✅ گرفتن elementها با
✅ گوش دادن به eventها مثل
✅ جلوگیری از refresh فرم با
✅ دستکاری DOM با
مثال زیر یک Todo List خیلی ساده ولی عملی است. کافیست یک فایل
نکتههای ریز 👇
• استفاده از
• با
• با
این تمرین پایه خوبی برای قدمهای بعدی مثل ذخیرهسازی در
امتحانش روی یک فایل ساده لوکال حس خوبی از «کار کردن کد» میدهد و درک DOM را خیلی محکمتر میکند. اگر به درد دوستی میخورد که تازه JavaScript را شروع کرده، برایش بفرست 💚
🔖 #Javascript #JS #جاوااسکریپت #JavaScript #DOM #Todo #Frontend #ES6 #VanillaJS
👤 Developix
💎 Channel: @DevelopixJavascript
خیلی وقتها برای تمرین JavaScript و DOM، یک پروژه کوچیک و واقعی مثل Todo List بهترین گزینهست. هم رویدادها رو لمس میکنی، هم کار با DOM و هم مدیریت state ساده رو.
یکی از بهترین رفرنسها برای کار با DOM و رویدادها، مستندات MDN هست:
MDN DOM Introduction
در این تمرین، با چند مفهوم مهم سر و کار داریم:
✅ گرفتن elementها با
querySelector✅ گوش دادن به eventها مثل
submit و click✅ جلوگیری از refresh فرم با
event.preventDefault()✅ دستکاری DOM با
createElement و appendChildمثال زیر یک Todo List خیلی ساده ولی عملی است. کافیست یک فایل
index.html بسازی و این کد را داخلش قرار بدهی و در مرورگر باز کنی:<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Simple Todo</title>
<style>
body { font-family: sans-serif; max-width: 480px; margin: 40px auto; }
form { display: flex; gap: 8px; }
ul { padding: 0; list-style: none; }
li { display: flex; justify-content: space-between; margin: 4px 0; }
button { cursor: pointer; }
</style>
</head>
<body>
<h1>Todo List</h1>
<form id="todo-form">
<input id="todo-input" placeholder="New task..." required />
<button type="submit">Add</button>
</form>
<ul id="todo-list"></ul>
<script>
const form = document.querySelector('#todo-form');
const input = document.querySelector('#todo-input');
const list = document.querySelector('#todo-list');
form.addEventListener('submit', function (event) {
event.preventDefault();
const text = input.value.trim();
if (!text) return;
const li = document.createElement('li');
const span = document.createElement('span');
span.textContent = text;
const removeBtn = document.createElement('button');
removeBtn.textContent = 'x';
removeBtn.addEventListener('click', function () {
list.removeChild(li);
});
li.appendChild(span);
li.appendChild(removeBtn);
list.appendChild(li);
input.value = '';
input.focus();
});
</script>
</body>
</html>
نکتههای ریز 👇
• استفاده از
trim() جلوی اضافه شدن تسک خالی را میگیرد.• با
event.preventDefault() فرم صفحه را reload نمیکند و کنترل دست ما میماند.• با
addEventListener روی خود دکمه حذف کار میکنیم تا ساختار کد تمیزتر بماند.این تمرین پایه خوبی برای قدمهای بعدی مثل ذخیرهسازی در
localStorage، اضافه کردن فیلتر (Completed / Active) یا بعداً پیادهسازی همین ایده در React یا Vue است.امتحانش روی یک فایل ساده لوکال حس خوبی از «کار کردن کد» میدهد و درک DOM را خیلی محکمتر میکند. اگر به درد دوستی میخورد که تازه JavaScript را شروع کرده، برایش بفرست 💚
🔖 #Javascript #JS #جاوااسکریپت #JavaScript #DOM #Todo #Frontend #ES6 #VanillaJS
👤 Developix
💎 Channel: @DevelopixJavascript
🔥6❤2
🎯 هندلکردن کلیکها با Event Delegation
وقتی تعداد زیادی دکمه یا آیتم در DOM داریم، اضافهکردن یک event listener روی هر عنصر هم کند است، هم کد را شلوغ میکند. با Event Delegation فقط روی والد گوش میدهیم و رویداد را از مسیر
✅ این کار:
• تعداد listenerها را کم میکند ✂️
• مدیریت عناصر اضافه/حذفشونده را ساده میکند
مثال ساده روی یک لیست:
حالا هر
برای جزئیات بیشتر: MDN - Event delegation
توی پروژههای سنگین DOM، این الگو هم خوانایی کد را بهتر میکند هم عملکرد را. 😉
🔖 #Javascript #JS #جاوااسکریپت #JavaScript #Event_Delegation #DOM #Performance #ES6
👤 Developix
💎 Channel: @DevelopixJavascript
وقتی تعداد زیادی دکمه یا آیتم در DOM داریم، اضافهکردن یک event listener روی هر عنصر هم کند است، هم کد را شلوغ میکند. با Event Delegation فقط روی والد گوش میدهیم و رویداد را از مسیر
event.target مدیریت میکنیم. 🔥✅ این کار:
• تعداد listenerها را کم میکند ✂️
• مدیریت عناصر اضافه/حذفشونده را ساده میکند
مثال ساده روی یک لیست:
const list = document.querySelector('#user-list');
list.addEventListener('click', (event) => {
const item = event.target.closest('li');
if (!item || !list.contains(item)) return;
const userId = item.dataset.userId;
console.log('Clicked user:', userId);
});
حالا هر
<li data-user-id="123"> که بعداً با JavaScript به #user-list اضافه شود، بدون نیاز به listener جدید، کلیک را هندل میکند. 🚀برای جزئیات بیشتر: MDN - Event delegation
توی پروژههای سنگین DOM، این الگو هم خوانایی کد را بهتر میکند هم عملکرد را. 😉
🔖 #Javascript #JS #جاوااسکریپت #JavaScript #Event_Delegation #DOM #Performance #ES6
👤 Developix
💎 Channel: @DevelopixJavascript
👍5❤1
در این نمونهکد، برای هر درخواست ورودی چندین بار JSON.parse روی
بهنظر شما در پروژههای واقعی، استفاده از این الگو چه مزیتهایی از نظر performance، قابلیت تست و کاهش ریسک Side Effect نسبت به پارس مستقیم JSON در هر هندلر دارد؟
🔖 #Javascript #JS #جاوااسکریپت
👤 Developix
💎 Channel: @DevelopixJavascript
req.body انجام میشود که میتواند در درخواستهای سنگین باعث کاهش کارایی، افزایش مصرف CPU و حتی بروز خطا در صورت خراب شدن ساختار بدنه شود. در مقابل، در نسخه اصلاحشده با استفاده از یک middleware اختصاصی، فقط یک بار پارس انجام شده و نتیجه در یک فیلد امن روی req ذخیره میشود.بهنظر شما در پروژههای واقعی، استفاده از این الگو چه مزیتهایی از نظر performance، قابلیت تست و کاهش ریسک Side Effect نسبت به پارس مستقیم JSON در هر هندلر دارد؟
🔖 #Javascript #JS #جاوااسکریپت
👤 Developix
💎 Channel: @DevelopixJavascript
👍2
خروجی این کد JavaScript چیست؟
به ترتیب و با دقت به event loop و صف microtask و macrotask فکر کنید و رشتهای را که در کنسول چاپ میشود، دقیقا به همان ترتیب بنویسید.
خروجی نهایی کنسول را دقیقا و به ترتیب، در یک خط یا چند خط، بنویسید.
🔖 #Javascript #JS #جاوااسکریپت
👤 Developix
💎 Channel: @DevelopixJavascript
به ترتیب و با دقت به event loop و صف microtask و macrotask فکر کنید و رشتهای را که در کنسول چاپ میشود، دقیقا به همان ترتیب بنویسید.
const p = Promise.resolve(1);
p.then(v => {
console.log("A", v);
return v + 1;
}).then(v => {
console.log("B", v);
return Promise.resolve(v + 1);
}).then(v => {
console.log("C", v);
});
setTimeout(() => {
console.log("D");
Promise.resolve().then(() => {
console.log("E");
});
}, 0);
console.log("F");
خروجی نهایی کنسول را دقیقا و به ترتیب، در یک خط یا چند خط، بنویسید.
🔖 #Javascript #JS #جاوااسکریپت
👤 Developix
💎 Channel: @DevelopixJavascript
در کد زیر سازندهی کلاس تلاش میکند با استفاده از
سؤال: در این کد چه چیزی باید تغییر کند تا اجرای غیرهمزمان بهدرستی منتظر اتمام تمام درخواستها بماند و سپس
🔖 #Javascript #JS #جاوااسکریپت
👤 Developix
💎 Channel: @DevelopixJavascript
async/await و forEach دادهها را بهصورت غیرهمزمان لود کند، اما رفتار نهایی با انتظار نویسندهی کد فرق دارد و this.data در زمان استفاده هنوز کامل مقداردهی نشده است.سؤال: در این کد چه چیزی باید تغییر کند تا اجرای غیرهمزمان بهدرستی منتظر اتمام تمام درخواستها بماند و سپس
this.data کامل آماده باشد؟class DataLoader {
constructor(apiUrls) {
this.data = [];
this.load(apiUrls);
}
async load(urls) {
urls.forEach(async (url) => {
const res = await fetch(url);
const json = await res.json();
this.data.push(json);
});
}
}
const loader = new DataLoader([
"https://example.com/api/users",
"https://example.com/api/posts"
]);
// بعداً در جایی دیگر:
console.log("Loaded:", loader.data.length); // مقدار اینجا غیرقابل اعتماد است🔖 #Javascript #JS #جاوااسکریپت
👤 Developix
💎 Channel: @DevelopixJavascript