برنامه نویسی

جاوا اسکریپت ناهمزمان – ابهامات را پاک کنید

Summarize this content to 400 words in Persian Lang
توجه: من کل موضوع را گام به گام توضیح داده ام، اما به راحتی به هر بخش که سؤالی دارید یا نیاز به توضیح دارید بروید.

قبل از اینکه وارد جاوا اسکریپت ناهمزمان شویم، مهم است که بفهمیم جاوا اسکریپت همزمان چیست و چرا برای نوشتن کد جاوا اسکریپت به روش ناهمزمان نیاز داریم، درست است؟

در برنامه نویسی همزمان، وظایف یکی پس از دیگری و به صورت متوالی اجرا می شوند. کار بعدی فقط پس از اتمام کار فعلی می تواند شروع شود. اگر یک کار زمان زیادی می برد، بقیه چیزها باید منتظر بمانند.

به آن مانند انتظار در صف یک فروشگاه مواد غذایی فکر کنید: اگر فرد مقابل شما موارد زیادی دارد و زمان زیادی طول می کشد تا بررسی شود، باید منتظر بمانید تا این موارد تمام شود تا بتوانید ادامه دهید.

console.log(“Start cooking”);

for (let i = 0; i < 5; i++) {
console.log(“Cooking dish ” + (i + 1));
}

console.log(“Finish cooking”);

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این چیزی است که اتفاق می افتد:

چاپ می کند “Start cooking”.
سپس وارد یک حلقه می شود و هر کدام را چاپ می کند “Cooking dish X” یکی پس از دیگری
فقط پس از اتمام حلقه، چاپ می شود “Finish cooking”.

در این حالت، کد به ترتیب اجرا می شود و تا زمانی که کار فعلی (پخت هر غذا) تکمیل نشود، هیچ اتفاق دیگری نمی افتد. تصور کنید پختن یک غذا 10 دقیقه طول بکشد – بقیه چیزها باید منتظر بمانند تا آن غذا تمام شود.

در برنامه نویسی ناهمزمان، وظایف را می توان شروع کرد، و در حالی که هنوز در حال اجرا هستند (مثلاً انتظار برای داده از یک سرور)، سایر وظایف می توانند به اجرا ادامه دهند. لازم نیست قبل از شروع کار دیگر منتظر بمانید تا یک کار تمام شود.

به آن مانند سفارش دادن در یک رستوران فکر کنید: غذای خود را سفارش می دهید و در حین آماده شدن می توانید به صحبت با دوستان خود ادامه دهید یا گوشی خود را چک کنید. پس از آماده شدن غذا، گارسون آن را برای شما می آورد.

مثالی از کد ناهمزمان:

console.log(“Start cooking”);

setTimeout(() => {
console.log(“Cooking is done!”);
}, 3000); // Simulate a task that takes 3 seconds

console.log(“Prepare other things while waiting”);

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این چیزی است که اتفاق می افتد:

چاپ می کند “Start cooking”.
را setTimeout عملکرد یک تایمر 3 ثانیه ای را شروع می کند. اما جاوا اسکریپت به جای منتظر ماندن بلافاصله به خط بعدی می رود.
چاپ می کند “Prepare other things while waiting”.
پس از 3 ثانیه، تایمر کامل شده و چاپ می شود “Cooking is done!”.

سه راه اصلی برای نوشتن جاوا اسکریپت ناهمزمان وجود دارد که عبارتند از:

تماس های تلفنی
وعده ها
Async/Await

اینها رویکردهای اولیه برای مدیریت کدهای ناهمزمان در جاوا اسکریپت هستند.

الف عملکرد برگشت به تماس در جاوا اسکریپت تابعی است که به عنوان آرگومان به تابع دیگری ارسال می کنید. ایده اصلی این است که شما یک تابع را به عنوان یک آرگومان به یک تابع دیگر منتقل یا تعریف می‌کنید، و آن تابع ارسال شده یک تابع Callback نامیده می‌شود. پس از اتمام یک کار خاص، اغلب پس از انجام یک کار ناهمزمان، مانند واکشی داده ها از یک سرور، تماس برگشتی فراخوانی می شود (یا “فراخوانی” می شود).

این به عملکرد اصلی شما اجازه می دهد تا بدون انتظار برای اتمام کار به انجام کارهای دیگر ادامه دهد. هنگامی که کار انجام شد، پاسخ تماس برای رسیدگی به نتیجه فعال می شود.

function mainFunc(callback){
console.log(“this is set before setTimeout”)
callback()
console.log(“this is set after setTimeout”)
}

function cb(){
setTimeout(()=>{
console.log(“This is supposed to be painted after 3 second”)
},3000)
}

mainFunc(cb)

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این کد نشان می دهد پاسخ به تماس مفهوم در جاوا اسکریپت در اینجا نحوه کار آن آمده است:

mainFunc الف می گیرد پاسخ به تماس به عنوان یک استدلال عمل کنید.
داخل mainFunc، پاسخ به تماس بلافاصله اجرا می شود، اما از آنجایی که پاسخ به تماس خود ( cb تابع) شامل a setTimeout، برنامه ریزی می کند console.log برای اجرا بعد از 3 ثانیه
در همین حال، mainFunc به اجرا ادامه می دهد، پیام ها را قبل و بعد از تماس پاسخ چاپ می کند.
بعد از 3 ثانیه، setTimeout در داخل پاسخ به تماس تمام می شود و پیام تاخیری چاپ می شود.

این نشان می دهد که چگونه تابع اصلی بدون منتظر ماندن برای تکمیل عملیات ناهمزمان (تأخیر 3 ثانیه ای در تماس برگشت) به وظایف خود ادامه می دهد.

Callback hell چیست و چه زمانی اتفاق می افتد؟

جهنم برگشت به تماس به موقعیتی در جاوا اسکریپت اشاره می کند که در آن چندین فراخوان به روشی غیرقابل مدیریت در داخل یکدیگر قرار می گیرند و خواندن، نگهداری و اشکال زدایی کد را دشوار می کند. اغلب شبیه هرمی از توابع تو در تو به نظر می رسد، که در آن هر عملیات ناهمزمان به تکمیل عملیات قبلی متکی است و منجر به تماس های عمیق تو در تو می شود.

جهنم برگشت به تماس معمولاً زمانی اتفاق می افتد که چندین کار ناهمزمان دارید که باید به ترتیب انجام شوند و هر کار به نتیجه قبلی بستگی دارد. با اضافه شدن وظایف بیشتر، کد به طور فزاینده‌ای فرورفته می‌شود و دنبال کردن آن سخت‌تر می‌شود و در نتیجه ساختاری آشفته و پیچیده ایجاد می‌شود.

getData((data) => {
processData(data, (processedData) => {
saveData(processedData, (savedData) => {
notifyUser(savedData, () => {
console.log(“All tasks complete!”);
});
});
});
});

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در اینجا، هر کار به کار قبلی وابسته است، که منجر به چندین سطح تورفتگی و منطقی دشوار می شود. اگر در هر نقطه ای خطایی وجود داشته باشد، مدیریت صحیح آن حتی پیچیده تر می شود.

جاوا اسکریپت مدرن برای نجات شما از جهنم برگشت به تماس، راه حل هایی از قبیل:

وعده ها – که کد را صاف می کند و آن را خواناتر می کند.
Async/Await – که زنجیره عملیات ناهمزمان را ساده می کند و کد را همزمان به نظر می رساند.

الف قول بده در جاوا اسکریپت یک شی است که نشان دهنده تکمیل (یا شکست) نهایی یک عملیات ناهمزمان و نتیجه آن است. این مثل یک است قول دادن شما در زندگی واقعی می سازید: ممکن است چیزی فوراً اتفاق نیفتد، اما شما یا آن را انجام می دهید یا در انجام آن شکست می خورید.

در جاوا اسکریپت، Promises به شما امکان می دهد کدهای ناهمزمان را به روشی تمیزتر بنویسید و اجتناب کنید جهنم برگشت به تماس. یک Promise با استفاده از new Promise نحو، و یک تابع (که تابع سازنده است) با دو پارامتر می گیرد: resolve (در صورت موفقیت آمیز بودن کار) و reject (اگر شکست بخورد).

const myPromise = new Promise((resolve, reject) => {
// Simulating an asynchronous task like fetching data
const success = true; // Change to false to simulate failure

setTimeout(() => {
if (success) {
resolve(“Task completed successfully!”); // Success
} else {
reject(“Task failed!”); // Failure
}
}, 2000); // 2-second delay
});

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اینجا:

وعده کاری را شبیه سازی می کند که 2 ثانیه طول می کشد.
در صورت موفقیت آمیز بودن کار (success است true) تماس می گیرد resolve با یک پیام
اگر شکست بخورد (success است false) تماس می گیرد reject با پیغام خطا

نحوه رسیدگی به یک قول

برای رسیدگی به نتیجه یک Promise از دو روش استفاده می کنیم:

myPromise
.then((message) => {
console.log(message); // “Task completed successfully!” (if resolve was called)
})
.catch((error) => {
console.log(error); // “Task failed!” (if reject was called)
});

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

زنجیر زدن در وعده ها

Promises به شما این امکان را می دهد که عملیات ناهمزمان را با استفاده از .then() روشی که کد را خطی تر و دنبال کردن آن آسان تر می کند. هر کدام .then() نشان دهنده مرحله ای در فرآیند ناهمزمان است. را .catch() روش به شما اجازه می دهد تا مدیریت خطا را در انتهای زنجیره وعده متمرکز کنید و آن را سازماندهی کنید.

fetchData()
.then(data => processData1(data))
.then(result1 => processData2(result1))
.then(result2 => processData3(result2))
.catch(error => handleError(error));

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Promises با اجتناب از تماس های عمیق تو در تو، ساختار کد قابل خواندن و قابل نگهداری تر را ترویج می کند. مکانیسم‌های زنجیره‌ای و مدیریت خطا به یک پایگاه کد واضح‌تر و سازمان‌یافته‌تر کمک می‌کنند.

// Callback hell
fetchData1(data1 => {
processData1(data1, result1 => {
fetchData2(result1, data2 => {
processData2(data2, result2 => {
fetchData3(result2, data3 => {
processData3(data3, finalResult => {
console.log(“Final result:”, finalResult);
});
});
});
});
});
});

// Using Promises
fetchData1()
.then(result1 => processData1(result1))
.then(data2 => fetchData2(data2))
.then(result2 => processData2(result2))
.then(data3 => fetchData3(data3))
.then(finalResult => {
console.log(“Final result:”, finalResult);
})
.catch(error => handleError(error));

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در نهایت روش

را در نهایت روش برای اجرای کد استفاده می شود، صرف نظر از اینکه Promise حل شود یا رد شود.

myPromise
.then((data) => {
console.log(“Data:”, data);
})
.catch((error) => {
console.error(“Error:”, error);
})
.finally(() => {
console.log(“Finally block”); // This runs no matter what
});

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اگر قول است برآورده شد (یعنی داده ها را با موفقیت دریافت می کند)، .then() روش اجرا خواهد شد. از سوی دیگر، اگر قول با خطا مواجه شود، .catch() متد برای رسیدگی به خطا فراخوانی می شود. با این حال، .finally() روش چنین شرطی ندارد – صرف نظر از اینکه وعده حل شده یا رد شده باشد، همیشه اجرا می شود. این که آیا .then() یا .catch() تحریک می شود، .finally() بلوک قطعا در پایان اجرا خواهد شد.

برای پاکسازی منابع، توقف بارگیری نشانگرها یا انجام کاری که باید پس از اتمام وعده اتفاق بیفتد، صرف نظر از نتیجه آن، مفید است.

روش های وعده جاوا اسکریپت

جاوا اسکریپت چندین مورد را فراهم می کند روش های قول دادن که کار با کارهای ناهمزمان را انعطاف پذیرتر و قدرتمندتر می کند. این روش ها به شما این امکان را می دهند که وعده های متعدد، وعده های زنجیره ای را انجام دهید یا با نتایج مختلف به روش های مختلف مقابله کنید

روش
توضیحات

همه (تکرارپذیر)
منتظر می ماند تا همه وعده ها حل شود یا هر یک رد شود.

همه حل شده (قابل تکرار)
صبر می کند تا همه وعده ها یا حل و فصل شوند یا رد شوند.

هر (قابل تکرار)
به محض تحقق هر یک از وعده‌ها، ارزش وعده را برمی‌گرداند.

نژاد (تکرارپذیر)
صبر می کند تا هر یک از وعده ها حل شود یا رد شود.

رد کردن (دلیل)
یک شی وعده جدید را که به دلیل ذکر شده رد شده است برمی گرداند.

حل کردن (ارزش)
یک شی وعده جدید را که با مقدار داده شده حل می شود، برمی گرداند.

Promise.all() – اجرای موازی

می توانید استفاده کنید Promise.all() برای اجرای چندین عملیات ناهمزمان به صورت همزمان و مدیریت نتایج آنها به صورت جمعی.

این متد آرایه ای از وعده ها را می گیرد و آنها را اجرا می کند به صورت موازی که یک وعده جدید را برمی گرداند. این Promise جدید با آرایه‌ای از مقادیر حل‌شده زمانی محقق می‌شود که همه وعده‌های ورودی محقق شده باشند، یا با دلیل اولین Promise رد شده، رد شود.

Copy code
const promise1 = Promise.resolve(10);
const promise2 = Promise.resolve(20);
const promise3 = Promise.resolve(30);

Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values); // [10, 20, 30] });

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اگر یکی از وعده ها رد شود، کل Promise.all() رد خواهد کرد:

const promise1 = Promise.resolve(10);
const promise2 = Promise.reject(“Error!”);

Promise.all([promise1, promise2])
.then((values) => {
console.log(values);
})
.catch((error) => {
console.log(error); // “Error!”
});

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Promise.allSettled()

این روش آرایه‌ای از وعده‌ها را می‌گیرد و پس از اتمام اجرای همه آنها، چه موفق یا ناکام، یک وعده جدید برمی‌گرداند. بر خلاف Promise.all()، اگر یک وعده شکست بخورد، شکست نمی خورد. در عوض، منتظر می ماند تا تمام وعده ها تکمیل شوند و مجموعه ای از نتایج را به شما می دهد که نشان می دهد هر کدام موفق بوده اند یا شکست خورده اند.

زمانی مفید است که می خواهید نتیجه آن را بدانید هر قول، حتی اگر برخی شکست بخورند.

const promise1 = Promise.resolve(“Success!”);
const promise2 = Promise.reject(“Failure!”);

Promise.allSettled([promise1, promise2]).then((results) => {
console.log(results);
// [{ status: ‘fulfilled’, value: ‘Success!’ }, { status: ‘rejected’, reason: ‘Failure!’ }] });

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Promise.any()

Promise.any() مجموعه‌ای از وعده‌ها را می‌گیرد و قولی را برمی‌گرداند که به‌محض رفع می‌شود هر قولی حل میشه اگر همه وعده های ورودی رد شوند، پس Promise.any() با یک رد می کند AggregateError حاوی مجموعه ای از دلایل رد

این مفید است زمانی که شما فقط نیاز دارید یک نتیجه موفق از قول های متعدد

const promise1 = fetchData1();
const promise2 = fetchData2();
const promise3 = fetchData3();

Promise.any([promise1, promise2, promise3])
.then((firstFulfilledValue) => {
console.log(“First promise fulfilled with:”, firstFulfilledValue);
})
.catch((allRejectedReasons) => {
console.error(“All promises rejected with:”, allRejectedReasons);
});

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Promise.race()

این روش آرایه‌ای از وعده‌ها را می‌گیرد و قول جدیدی را که برطرف یا رد می‌کند، برمی‌گرداند به محض اینکه اولین وعده حل شد (یا حل می کند یا رد می کند).

زمانی مفید است که می‌خواهید نتیجه سریع‌ترین وعده را داشته باشید و دیگران را نادیده بگیرید.

const promise1 = new Promise((resolve) => setTimeout(resolve, 100, “First”));
const promise2 = new Promise((resolve) => setTimeout(resolve, 200, “Second”));

Promise.race([promise1, promise2]).then((value) => {
console.log(value); // “First” (because promise1 resolves first)
});

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Promise.resolve()

این روش بلافاصله حل می شود وعده ای با ارزش معین این برای ایجاد قولی مفید است که از قبل می دانید محقق خواهد شد.

const resolvedPromise = Promise.resolve(“Resolved!”);
resolvedPromise.then((value) => {
console.log(value); // “Resolved!”
});

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Promise.reject()

این روش بلافاصله رد می کند قولی با خطا یا دلیل معین این برای ایجاد قولی مفید است که می دانید شکست خواهد خورد.

const rejectedPromise = Promise.reject(“Rejected!”);
rejectedPromise.catch((error) => {
console.log(error); // “Rejected!”
});

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

امیدوارم بعد از مطالعه دقیق این توضیح وعده ها هیچ سردرگمی در مورد وعده ها نداشته باشید. اکنون، زمان آن است که به جلو برویم Async/Await.

async / await یک روش مدرن برای مدیریت عملیات ناهمزمان در جاوا اسکریپت است که در ES2017 (ES8) معرفی شده است. در بالای آن ساخته شده است وعده ها اما یک نحو تمیزتر و خواناتر را ارائه می دهد و باعث می شود کد ناهمزمان بیشتر شبیه کد همزمان به نظر برسد و رفتار کند. این امر درک و رفع اشکال را آسان تر می کند.

چگونه async و await کار کنید

وقتی تابعی را با async کلمه کلیدی، همیشه a را برمی گرداند قول بده. حتی اگر به صراحت وعده ای را برنگردانید، جاوا اسکریپت مقدار بازگشتی را در یک وعده حل شده قرار می دهد.

را await کلمه کلیدی را فقط می توان در داخل یک استفاده کرد async تابع جاوا اسکریپت را می سازد صبر کن برای وعده حل قبل از رفتن به خط بعدی کد. اجرای تابع را “مکث” می کند و به شما امکان می دهد تا کارهای ناهمزمان را به صورت متوالی تری انجام دهید، درست مانند کدهای همزمان.

بیایید به یک مثال ساده نگاه کنیم تا ببینیم چگونه این کار می کند:

async function fetchData() {
try {
const response = await fetch(“https://api.example.com/data”);
const data = await response.json();
console.log(“Data:”, data);
} catch (error) {
console.error(“Error fetching data:”, error);
} finally {
console.log(“Fetch operation complete”);
}
}

fetchData();

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

چگونه کار می کند:

async تابع: از آنجایی که fetchData تابع به عنوان علامت گذاری شده است async، یعنی یک وعده را برمی گرداند.
await fetch(): await اجرای تابع را تا زمان بازگشت وعده توسط متوقف می کند fetch() حل می کند. سپس پس از حل شدن وعده، با خط بعدی ادامه می یابد.
try/catch: از a استفاده می کنیم try/catch مسدود کردن برای رسیدگی به هرگونه خطای احتمالی در طول عملیات همگام سازی.
finally: صرف نظر از موفقیت یا شکست، finally بلوک اجرا خواهد شد.

چرا استفاده کنید async / await?

با async/await، کد شما خواناتر می شود و به صورت طبیعی تر جریان می یابد. این امر پیروی از منطق را آسان‌تر می‌کند، به‌ویژه هنگامی که با چندین عملیات ناهمزمان سر و کار دارید.

این را با رسیدگی به وعده ها مقایسه کنید .then():

fetch(“https://api.example.com/data”)
.then(response => response.json())
.then(data => {
console.log(“Data:”, data);
})
.catch(error => {
console.error(“Error fetching data:”, error);
})
.finally(() => {
console.log(“Fetch operation complete”);
});

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

را async/await نسخه تمیزتر و قابل درک تر به نظر می رسد. async/await کمک می کند تا از تودرتوی تماس های برگشتی یا .then() زنجیره‌ها، کد شما را خطی‌تر و دنبال کردن آن آسان‌تر می‌کند.

مثال با Multiple await

شما همچنین می توانید چندین کار ناهمزمان را به صورت متوالی بدون نیاز به زنجیره ای از وعده ها انجام دهید.

async function processOrders() {
const user = await getUserDetails(); // Waits for user details
const orders = await getOrders(user.id); // Waits for orders
console.log(“Orders:”, orders);
}

processOrders();

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در این مثال، تابع منتظر می‌ماند تا هر کار قبل از رفتن به کار بعدی تمام شود، درست مانند نحوه رفتار کد همزمان.

اجرای موازی با Promise.all() و async/await

اگر می خواهید چندین عملیات ناهمزمان را انجام دهید در همان زمان (به صورت موازی)، هنوز هم می توانید استفاده کنید Promise.all() با async/await:

async function getAllData() {
const [user, orders] = await Promise.all([getUserDetails(), getOrders()]);
console.log(“User:”, user);
console.log(“Orders:”, orders);
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اینجا، هر دو getUserDetails() و getOrders() به طور همزمان اجرا می شود و این تابع قبل از ثبت نتایج منتظر می ماند تا هر دو به پایان برسند.

در جاوا اسکریپت، مدیریت عملیات ناهمزمان در طول زمان تکامل یافته است و ابزارهای مختلفی را برای مدیریت پذیرتر و کارآمدتر کردن کد ارائه می دهد. تماس های تلفنی اولین رویکرد بود، اما با افزایش پیچیدگی کد، اغلب به مسائلی مانند “جهنم پاسخ به تماس” منجر می شد. وعده ها در مرحله بعدی قرار گرفت و روشی تمیزتر و ساختارمندتر برای مدیریت کارهای ناهمگام ارائه کرد .then() و .catch()، بهبود خوانایی و کاهش تودرتو.

در نهایت، همگام سازی/انتظار به عنوان یک نحو مدرن که بر اساس وعده‌ها ساخته شده است، معرفی شد و باعث می‌شود کد ناهمزمان بیشتر شبیه کد همزمان به نظر برسد. این فرآیند را حتی بیشتر ساده می کند و به کدهایی با خوانایی آسان تر و قابل نگهداری تر اجازه می دهد. هر یک از این تکنیک‌ها نقش مهمی در جاوا اسکریپت دارند و تسلط بر آن‌ها به شما کمک می‌کند کد کارآمدتر، واضح‌تر و قوی‌تر بنویسید.

درک زمان استفاده از هر روش – پاسخ به تماس برای کارهای ساده، وعده‌هایی برای مدیریت ساختاریافته، و غیر همگام‌سازی/انتظار برای کدهای همگام‌سازی قابل خواندن و مقیاس‌پذیر – به شما این امکان را می‌دهد که بهترین انتخاب‌ها را برای پروژه‌های خود داشته باشید.

من قبلاً با مفهوم قول، به خصوص روش های مختلف قول، گیج می شدم. پاسخ به تماس برای من یک چالش بزرگ بود زیرا نحو همیشه بسیار گیج کننده به نظر می رسید. بنابراین، من منابع مختلف آنلاین، از جمله ربات‌های گفتگو، را خواندم تا به این شرح برسم. صادقانه بگویم، چت بات ها همیشه پاسخی مستقیم و قابل فهم ارائه نمی دهند. بنابراین، من فقط از جاهای مختلف کپی و پیست نکردم – همه چیز را ساده کردم تا بتواند به عنوان یک یادداشت واضح برای من و هر کس دیگری که در درک این مفاهیم مشکل دارد باشد. امیدوارم این یادداشت شما را با سردرگمی صفر رها کند.

توجه: من کل موضوع را گام به گام توضیح داده ام، اما به راحتی به هر بخش که سؤالی دارید یا نیاز به توضیح دارید بروید.

قبل از اینکه وارد جاوا اسکریپت ناهمزمان شویم، مهم است که بفهمیم جاوا اسکریپت همزمان چیست و چرا برای نوشتن کد جاوا اسکریپت به روش ناهمزمان نیاز داریم، درست است؟

در برنامه نویسی همزمان، وظایف یکی پس از دیگری و به صورت متوالی اجرا می شوند. کار بعدی فقط پس از اتمام کار فعلی می تواند شروع شود. اگر یک کار زمان زیادی می برد، بقیه چیزها باید منتظر بمانند.

به آن مانند انتظار در صف یک فروشگاه مواد غذایی فکر کنید: اگر فرد مقابل شما موارد زیادی دارد و زمان زیادی طول می کشد تا بررسی شود، باید منتظر بمانید تا این موارد تمام شود تا بتوانید ادامه دهید.

console.log("Start cooking");

for (let i = 0; i < 5; i++) {
  console.log("Cooking dish " + (i + 1));
}

console.log("Finish cooking");
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این چیزی است که اتفاق می افتد:

  1. چاپ می کند "Start cooking".

  2. سپس وارد یک حلقه می شود و هر کدام را چاپ می کند "Cooking dish X" یکی پس از دیگری

  3. فقط پس از اتمام حلقه، چاپ می شود "Finish cooking".

در این حالت، کد به ترتیب اجرا می شود و تا زمانی که کار فعلی (پخت هر غذا) تکمیل نشود، هیچ اتفاق دیگری نمی افتد. تصور کنید پختن یک غذا 10 دقیقه طول بکشد – بقیه چیزها باید منتظر بمانند تا آن غذا تمام شود.

در برنامه نویسی ناهمزمان، وظایف را می توان شروع کرد، و در حالی که هنوز در حال اجرا هستند (مثلاً انتظار برای داده از یک سرور)، سایر وظایف می توانند به اجرا ادامه دهند. لازم نیست قبل از شروع کار دیگر منتظر بمانید تا یک کار تمام شود.

به آن مانند سفارش دادن در یک رستوران فکر کنید: غذای خود را سفارش می دهید و در حین آماده شدن می توانید به صحبت با دوستان خود ادامه دهید یا گوشی خود را چک کنید. پس از آماده شدن غذا، گارسون آن را برای شما می آورد.

مثالی از کد ناهمزمان:

console.log("Start cooking");

setTimeout(() => {
  console.log("Cooking is done!");
}, 3000); // Simulate a task that takes 3 seconds

console.log("Prepare other things while waiting");
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این چیزی است که اتفاق می افتد:

  1. چاپ می کند "Start cooking".

  2. را setTimeout عملکرد یک تایمر 3 ثانیه ای را شروع می کند. اما جاوا اسکریپت به جای منتظر ماندن بلافاصله به خط بعدی می رود.

  3. چاپ می کند "Prepare other things while waiting".

  4. پس از 3 ثانیه، تایمر کامل شده و چاپ می شود "Cooking is done!".


سه راه اصلی برای نوشتن جاوا اسکریپت ناهمزمان وجود دارد که عبارتند از:

  1. تماس های تلفنی

  2. وعده ها

  3. Async/Await

اینها رویکردهای اولیه برای مدیریت کدهای ناهمزمان در جاوا اسکریپت هستند.

الف عملکرد برگشت به تماس در جاوا اسکریپت تابعی است که به عنوان آرگومان به تابع دیگری ارسال می کنید. ایده اصلی این است که شما یک تابع را به عنوان یک آرگومان به یک تابع دیگر منتقل یا تعریف می‌کنید، و آن تابع ارسال شده یک تابع Callback نامیده می‌شود. پس از اتمام یک کار خاص، اغلب پس از انجام یک کار ناهمزمان، مانند واکشی داده ها از یک سرور، تماس برگشتی فراخوانی می شود (یا “فراخوانی” می شود).

این به عملکرد اصلی شما اجازه می دهد تا بدون انتظار برای اتمام کار به انجام کارهای دیگر ادامه دهد. هنگامی که کار انجام شد، پاسخ تماس برای رسیدگی به نتیجه فعال می شود.

function mainFunc(callback){
  console.log("this is set before setTimeout")
  callback()
  console.log("this is set after setTimeout")
}

function cb(){
  setTimeout(()=>{
    console.log("This is supposed to be painted after 3 second")
  },3000)
}

mainFunc(cb)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این کد نشان می دهد پاسخ به تماس مفهوم در جاوا اسکریپت در اینجا نحوه کار آن آمده است:

  1. mainFunc الف می گیرد پاسخ به تماس به عنوان یک استدلال عمل کنید.

  2. داخل mainFunc، پاسخ به تماس بلافاصله اجرا می شود، اما از آنجایی که پاسخ به تماس خود ( cb تابع) شامل a setTimeout، برنامه ریزی می کند console.log برای اجرا بعد از 3 ثانیه

  3. در همین حال، mainFunc به اجرا ادامه می دهد، پیام ها را قبل و بعد از تماس پاسخ چاپ می کند.

  4. بعد از 3 ثانیه، setTimeout در داخل پاسخ به تماس تمام می شود و پیام تاخیری چاپ می شود.

این نشان می دهد که چگونه تابع اصلی بدون منتظر ماندن برای تکمیل عملیات ناهمزمان (تأخیر 3 ثانیه ای در تماس برگشت) به وظایف خود ادامه می دهد.

Callback hell چیست و چه زمانی اتفاق می افتد؟

جهنم برگشت به تماس به موقعیتی در جاوا اسکریپت اشاره می کند که در آن چندین فراخوان به روشی غیرقابل مدیریت در داخل یکدیگر قرار می گیرند و خواندن، نگهداری و اشکال زدایی کد را دشوار می کند. اغلب شبیه هرمی از توابع تو در تو به نظر می رسد، که در آن هر عملیات ناهمزمان به تکمیل عملیات قبلی متکی است و منجر به تماس های عمیق تو در تو می شود.

جهنم برگشت به تماس معمولاً زمانی اتفاق می افتد که چندین کار ناهمزمان دارید که باید به ترتیب انجام شوند و هر کار به نتیجه قبلی بستگی دارد. با اضافه شدن وظایف بیشتر، کد به طور فزاینده‌ای فرورفته می‌شود و دنبال کردن آن سخت‌تر می‌شود و در نتیجه ساختاری آشفته و پیچیده ایجاد می‌شود.

getData((data) => {
  processData(data, (processedData) => {
    saveData(processedData, (savedData) => {
      notifyUser(savedData, () => {
        console.log("All tasks complete!");
      });
    });
  });
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در اینجا، هر کار به کار قبلی وابسته است، که منجر به چندین سطح تورفتگی و منطقی دشوار می شود. اگر در هر نقطه ای خطایی وجود داشته باشد، مدیریت صحیح آن حتی پیچیده تر می شود.

جاوا اسکریپت مدرن برای نجات شما از جهنم برگشت به تماس، راه حل هایی از قبیل:

  1. وعده ها – که کد را صاف می کند و آن را خواناتر می کند.

  2. Async/Await – که زنجیره عملیات ناهمزمان را ساده می کند و کد را همزمان به نظر می رساند.

الف قول بده در جاوا اسکریپت یک شی است که نشان دهنده تکمیل (یا شکست) نهایی یک عملیات ناهمزمان و نتیجه آن است. این مثل یک است قول دادن شما در زندگی واقعی می سازید: ممکن است چیزی فوراً اتفاق نیفتد، اما شما یا آن را انجام می دهید یا در انجام آن شکست می خورید.

در جاوا اسکریپت، Promises به شما امکان می دهد کدهای ناهمزمان را به روشی تمیزتر بنویسید و اجتناب کنید جهنم برگشت به تماس. یک Promise با استفاده از new Promise نحو، و یک تابع (که تابع سازنده است) با دو پارامتر می گیرد: resolve (در صورت موفقیت آمیز بودن کار) و reject (اگر شکست بخورد).

const myPromise = new Promise((resolve, reject) => {
  // Simulating an asynchronous task like fetching data
  const success = true; // Change to false to simulate failure

  setTimeout(() => {
    if (success) {
      resolve("Task completed successfully!"); // Success
    } else {
      reject("Task failed!"); // Failure
    }
  }, 2000); // 2-second delay
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اینجا:

  • وعده کاری را شبیه سازی می کند که 2 ثانیه طول می کشد.

  • در صورت موفقیت آمیز بودن کار (success است true) تماس می گیرد resolve با یک پیام

  • اگر شکست بخورد (success است false) تماس می گیرد reject با پیغام خطا

نحوه رسیدگی به یک قول

برای رسیدگی به نتیجه یک Promise از دو روش استفاده می کنیم:

myPromise
  .then((message) => {
    console.log(message); // "Task completed successfully!" (if resolve was called)
  })
  .catch((error) => {
    console.log(error); // "Task failed!" (if reject was called)
  });
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

زنجیر زدن در وعده ها

Promises به شما این امکان را می دهد که عملیات ناهمزمان را با استفاده از .then() روشی که کد را خطی تر و دنبال کردن آن آسان تر می کند. هر کدام .then() نشان دهنده مرحله ای در فرآیند ناهمزمان است. را .catch() روش به شما اجازه می دهد تا مدیریت خطا را در انتهای زنجیره وعده متمرکز کنید و آن را سازماندهی کنید.

fetchData()
  .then(data => processData1(data))
  .then(result1 => processData2(result1))
  .then(result2 => processData3(result2))
  .catch(error => handleError(error));
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Promises با اجتناب از تماس های عمیق تو در تو، ساختار کد قابل خواندن و قابل نگهداری تر را ترویج می کند. مکانیسم‌های زنجیره‌ای و مدیریت خطا به یک پایگاه کد واضح‌تر و سازمان‌یافته‌تر کمک می‌کنند.

// Callback hell
fetchData1(data1 => {
  processData1(data1, result1 => {
    fetchData2(result1, data2 => {
      processData2(data2, result2 => {
        fetchData3(result2, data3 => {
          processData3(data3, finalResult => {
            console.log("Final result:", finalResult);
          });
        });
      });
    });
  });
});

// Using Promises
fetchData1()
  .then(result1 => processData1(result1))
  .then(data2 => fetchData2(data2))
  .then(result2 => processData2(result2))
  .then(data3 => fetchData3(data3))
  .then(finalResult => {
    console.log("Final result:", finalResult);
  })
  .catch(error => handleError(error));
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در نهایت روش

را در نهایت روش برای اجرای کد استفاده می شود، صرف نظر از اینکه Promise حل شود یا رد شود.

myPromise
  .then((data) => {
    console.log("Data:", data);
  })
  .catch((error) => {
    console.error("Error:", error);
  })
  .finally(() => {
    console.log("Finally block"); // This runs no matter what
  });
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اگر قول است برآورده شد (یعنی داده ها را با موفقیت دریافت می کند)، .then() روش اجرا خواهد شد. از سوی دیگر، اگر قول با خطا مواجه شود، .catch() متد برای رسیدگی به خطا فراخوانی می شود. با این حال، .finally() روش چنین شرطی ندارد – صرف نظر از اینکه وعده حل شده یا رد شده باشد، همیشه اجرا می شود. این که آیا .then() یا .catch() تحریک می شود، .finally() بلوک قطعا در پایان اجرا خواهد شد.

برای پاکسازی منابع، توقف بارگیری نشانگرها یا انجام کاری که باید پس از اتمام وعده اتفاق بیفتد، صرف نظر از نتیجه آن، مفید است.

روش های وعده جاوا اسکریپت

جاوا اسکریپت چندین مورد را فراهم می کند روش های قول دادن که کار با کارهای ناهمزمان را انعطاف پذیرتر و قدرتمندتر می کند. این روش ها به شما این امکان را می دهند که وعده های متعدد، وعده های زنجیره ای را انجام دهید یا با نتایج مختلف به روش های مختلف مقابله کنید

روشتوضیحات
همه (تکرارپذیر)منتظر می ماند تا همه وعده ها حل شود یا هر یک رد شود.
همه حل شده (قابل تکرار)صبر می کند تا همه وعده ها یا حل و فصل شوند یا رد شوند.
هر (قابل تکرار)به محض تحقق هر یک از وعده‌ها، ارزش وعده را برمی‌گرداند.
نژاد (تکرارپذیر)صبر می کند تا هر یک از وعده ها حل شود یا رد شود.
رد کردن (دلیل)یک شی وعده جدید را که به دلیل ذکر شده رد شده است برمی گرداند.
حل کردن (ارزش)یک شی وعده جدید را که با مقدار داده شده حل می شود، برمی گرداند.

Promise.all() – اجرای موازی

می توانید استفاده کنید Promise.all() برای اجرای چندین عملیات ناهمزمان به صورت همزمان و مدیریت نتایج آنها به صورت جمعی.

این متد آرایه ای از وعده ها را می گیرد و آنها را اجرا می کند به صورت موازی که یک وعده جدید را برمی گرداند. این Promise جدید با آرایه‌ای از مقادیر حل‌شده زمانی محقق می‌شود که همه وعده‌های ورودی محقق شده باشند، یا با دلیل اولین Promise رد شده، رد شود.


Copy code
const promise1 = Promise.resolve(10);
const promise2 = Promise.resolve(20);
const promise3 = Promise.resolve(30);

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values); // [10, 20, 30]
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اگر یکی از وعده ها رد شود، کل Promise.all() رد خواهد کرد:

const promise1 = Promise.resolve(10);
const promise2 = Promise.reject("Error!");

Promise.all([promise1, promise2])
  .then((values) => {
    console.log(values);
  })
  .catch((error) => {
    console.log(error); // "Error!"
  });
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Promise.allSettled()

این روش آرایه‌ای از وعده‌ها را می‌گیرد و پس از اتمام اجرای همه آنها، چه موفق یا ناکام، یک وعده جدید برمی‌گرداند. بر خلاف Promise.all()، اگر یک وعده شکست بخورد، شکست نمی خورد. در عوض، منتظر می ماند تا تمام وعده ها تکمیل شوند و مجموعه ای از نتایج را به شما می دهد که نشان می دهد هر کدام موفق بوده اند یا شکست خورده اند.

زمانی مفید است که می خواهید نتیجه آن را بدانید هر قول، حتی اگر برخی شکست بخورند.

const promise1 = Promise.resolve("Success!");
const promise2 = Promise.reject("Failure!");

Promise.allSettled([promise1, promise2]).then((results) => {
  console.log(results);
  // [{ status: 'fulfilled', value: 'Success!' }, { status: 'rejected', reason: 'Failure!' }]
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Promise.any()

Promise.any() مجموعه‌ای از وعده‌ها را می‌گیرد و قولی را برمی‌گرداند که به‌محض رفع می‌شود هر قولی حل میشه اگر همه وعده های ورودی رد شوند، پس Promise.any() با یک رد می کند AggregateError حاوی مجموعه ای از دلایل رد

این مفید است زمانی که شما فقط نیاز دارید یک نتیجه موفق از قول های متعدد

const promise1 = fetchData1();
const promise2 = fetchData2();
const promise3 = fetchData3();

Promise.any([promise1, promise2, promise3])
  .then((firstFulfilledValue) => {
    console.log("First promise fulfilled with:", firstFulfilledValue);
  })
  .catch((allRejectedReasons) => {
    console.error("All promises rejected with:", allRejectedReasons);
  });
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Promise.race()

این روش آرایه‌ای از وعده‌ها را می‌گیرد و قول جدیدی را که برطرف یا رد می‌کند، برمی‌گرداند به محض اینکه اولین وعده حل شد (یا حل می کند یا رد می کند).

زمانی مفید است که می‌خواهید نتیجه سریع‌ترین وعده را داشته باشید و دیگران را نادیده بگیرید.

const promise1 = new Promise((resolve) => setTimeout(resolve, 100, "First"));
const promise2 = new Promise((resolve) => setTimeout(resolve, 200, "Second"));

Promise.race([promise1, promise2]).then((value) => {
  console.log(value); // "First" (because promise1 resolves first)
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Promise.resolve()

این روش بلافاصله حل می شود وعده ای با ارزش معین این برای ایجاد قولی مفید است که از قبل می دانید محقق خواهد شد.

const resolvedPromise = Promise.resolve("Resolved!");
resolvedPromise.then((value) => {
  console.log(value); // "Resolved!"
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Promise.reject()

این روش بلافاصله رد می کند قولی با خطا یا دلیل معین این برای ایجاد قولی مفید است که می دانید شکست خواهد خورد.

const rejectedPromise = Promise.reject("Rejected!");
rejectedPromise.catch((error) => {
  console.log(error); // "Rejected!"
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

امیدوارم بعد از مطالعه دقیق این توضیح وعده ها هیچ سردرگمی در مورد وعده ها نداشته باشید. اکنون، زمان آن است که به جلو برویم Async/Await.

async / await یک روش مدرن برای مدیریت عملیات ناهمزمان در جاوا اسکریپت است که در ES2017 (ES8) معرفی شده است. در بالای آن ساخته شده است وعده ها اما یک نحو تمیزتر و خواناتر را ارائه می دهد و باعث می شود کد ناهمزمان بیشتر شبیه کد همزمان به نظر برسد و رفتار کند. این امر درک و رفع اشکال را آسان تر می کند.

چگونه async و await کار کنید

وقتی تابعی را با async کلمه کلیدی، همیشه a را برمی گرداند قول بده. حتی اگر به صراحت وعده ای را برنگردانید، جاوا اسکریپت مقدار بازگشتی را در یک وعده حل شده قرار می دهد.

را await کلمه کلیدی را فقط می توان در داخل یک استفاده کرد async تابع جاوا اسکریپت را می سازد صبر کن برای وعده حل قبل از رفتن به خط بعدی کد. اجرای تابع را “مکث” می کند و به شما امکان می دهد تا کارهای ناهمزمان را به صورت متوالی تری انجام دهید، درست مانند کدهای همزمان.

بیایید به یک مثال ساده نگاه کنیم تا ببینیم چگونه این کار می کند:

async function fetchData() {
  try {
    const response = await fetch("https://api.example.com/data");
    const data = await response.json();
    console.log("Data:", data);
  } catch (error) {
    console.error("Error fetching data:", error);
  } finally {
    console.log("Fetch operation complete");
  }
}

fetchData();
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

چگونه کار می کند:

  1. async تابع: از آنجایی که fetchData تابع به عنوان علامت گذاری شده است async، یعنی یک وعده را برمی گرداند.

  2. await fetch(): await اجرای تابع را تا زمان بازگشت وعده توسط متوقف می کند fetch() حل می کند. سپس پس از حل شدن وعده، با خط بعدی ادامه می یابد.

  3. try/catch: از a استفاده می کنیم try/catch مسدود کردن برای رسیدگی به هرگونه خطای احتمالی در طول عملیات همگام سازی.

  4. finally: صرف نظر از موفقیت یا شکست، finally بلوک اجرا خواهد شد.

چرا استفاده کنید async / await?

با async/await، کد شما خواناتر می شود و به صورت طبیعی تر جریان می یابد. این امر پیروی از منطق را آسان‌تر می‌کند، به‌ویژه هنگامی که با چندین عملیات ناهمزمان سر و کار دارید.

این را با رسیدگی به وعده ها مقایسه کنید .then():

fetch("https://api.example.com/data")
  .then(response => response.json())
  .then(data => {
    console.log("Data:", data);
  })
  .catch(error => {
    console.error("Error fetching data:", error);
  })
  .finally(() => {
    console.log("Fetch operation complete");
  });
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

را async/await نسخه تمیزتر و قابل درک تر به نظر می رسد. async/await کمک می کند تا از تودرتوی تماس های برگشتی یا .then() زنجیره‌ها، کد شما را خطی‌تر و دنبال کردن آن آسان‌تر می‌کند.

مثال با Multiple await

شما همچنین می توانید چندین کار ناهمزمان را به صورت متوالی بدون نیاز به زنجیره ای از وعده ها انجام دهید.

async function processOrders() {
  const user = await getUserDetails();  // Waits for user details
  const orders = await getOrders(user.id);  // Waits for orders
  console.log("Orders:", orders);
}

processOrders();
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در این مثال، تابع منتظر می‌ماند تا هر کار قبل از رفتن به کار بعدی تمام شود، درست مانند نحوه رفتار کد همزمان.

اجرای موازی با Promise.all() و async/await

اگر می خواهید چندین عملیات ناهمزمان را انجام دهید در همان زمان (به صورت موازی)، هنوز هم می توانید استفاده کنید Promise.all() با async/await:

async function getAllData() {
  const [user, orders] = await Promise.all([getUserDetails(), getOrders()]);
  console.log("User:", user);
  console.log("Orders:", orders);
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اینجا، هر دو getUserDetails() و getOrders() به طور همزمان اجرا می شود و این تابع قبل از ثبت نتایج منتظر می ماند تا هر دو به پایان برسند.

در جاوا اسکریپت، مدیریت عملیات ناهمزمان در طول زمان تکامل یافته است و ابزارهای مختلفی را برای مدیریت پذیرتر و کارآمدتر کردن کد ارائه می دهد. تماس های تلفنی اولین رویکرد بود، اما با افزایش پیچیدگی کد، اغلب به مسائلی مانند “جهنم پاسخ به تماس” منجر می شد. وعده ها در مرحله بعدی قرار گرفت و روشی تمیزتر و ساختارمندتر برای مدیریت کارهای ناهمگام ارائه کرد .then() و .catch()، بهبود خوانایی و کاهش تودرتو.

در نهایت، همگام سازی/انتظار به عنوان یک نحو مدرن که بر اساس وعده‌ها ساخته شده است، معرفی شد و باعث می‌شود کد ناهمزمان بیشتر شبیه کد همزمان به نظر برسد. این فرآیند را حتی بیشتر ساده می کند و به کدهایی با خوانایی آسان تر و قابل نگهداری تر اجازه می دهد. هر یک از این تکنیک‌ها نقش مهمی در جاوا اسکریپت دارند و تسلط بر آن‌ها به شما کمک می‌کند کد کارآمدتر، واضح‌تر و قوی‌تر بنویسید.

درک زمان استفاده از هر روش – پاسخ به تماس برای کارهای ساده، وعده‌هایی برای مدیریت ساختاریافته، و غیر همگام‌سازی/انتظار برای کدهای همگام‌سازی قابل خواندن و مقیاس‌پذیر – به شما این امکان را می‌دهد که بهترین انتخاب‌ها را برای پروژه‌های خود داشته باشید.

من قبلاً با مفهوم قول، به خصوص روش های مختلف قول، گیج می شدم. پاسخ به تماس برای من یک چالش بزرگ بود زیرا نحو همیشه بسیار گیج کننده به نظر می رسید. بنابراین، من منابع مختلف آنلاین، از جمله ربات‌های گفتگو، را خواندم تا به این شرح برسم. صادقانه بگویم، چت بات ها همیشه پاسخی مستقیم و قابل فهم ارائه نمی دهند. بنابراین، من فقط از جاهای مختلف کپی و پیست نکردم – همه چیز را ساده کردم تا بتواند به عنوان یک یادداشت واضح برای من و هر کس دیگری که در درک این مفاهیم مشکل دارد باشد. امیدوارم این یادداشت شما را با سردرگمی صفر رها کند.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا