| کانال توسعه‌دهندگان جاوااسکریپت |
3.83K subscribers
37 photos
2 videos
28 links
⭕️ کانال توسعه‌دهندگان جاوااسکریپت دولوپیکس

💠 دولوپیکس | جامعه توسعه‌دهندگان ایرانی

💎 @Developix
🚀 Developix.ir

📌 پشتیبانی و تبلیغات:
@DevelopixSupport
Download Telegram
در کد زیر توسعه‌دهنده می‌خواهد یک حلقه از توابع async بسازد که به‌ترتیب و با فاصله زمانی اجرا شوند، اما نتیجه‌ی نهایی آرایه‌ای خالی یا ناقص برمی‌گردد و همه‌ی async ها درست منتظر نمی‌مانند.

سوال: در این کد چه چیزی باید اصلاح شود تا 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 درست اجرا شوند و مقدار نهایی 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

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👎32
ساخت یک Todo List ساده با JavaScript خالص (بدون Framework)

خیلی وقت‌ها برای تمرین 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