Ahmadreza Mozaffary
Ahmadreza Mozaffary
خواندن ۱۱ دقیقه·۳ سال پیش

بهترین روش درخواست AJAX چیست؟ یک بار برای همیشه ! ( AJAX call )

سلام رفقا حالتون چطوره ؟

بدون وقفه بریم سر اصل مطلب ‌، که بخاطرش این صفحه رو باز کردید ...

احمدرضا مظفری هستم و ما توی این مقاله میخوایم باهم بررسی کنیم که کدوم یکی از روش های ارسال درخواست AJAX به سرور برای ما بهتر هست ، منظورم از اینکه برای ما بهتر هست اینه که هم کد بروز تری رو بنویسیم و هم خوانایی کد در آینده به مراتب بالا تر باشه و سردرگمی کمتری رو داشته باشیم ?

برای همین منظور ، اول همه روش های اصلی رو بررسی میکنیم بعد معایب اون ها رو میبینیم و در آخر بهترین روش رو به عنوان قهرمان و پیروز این مقاله معرفی میکنیم :)

 احمدرضا مظفری | Asynchronous JavaScript And XML
احمدرضا مظفری | Asynchronous JavaScript And XML

اگه که بخام به صورت خیلی کلی خدمتتون بگم ‌، باید عرض کنم که جاواسکریپت برای ارسال درخواست های ایجکس (‌ AJAX )‌ ، به ما ، استفاده از دوتا کانسپت کلی رو پیشنهاد کرده که امروزه به شدت از اونا توی بازار کار ،‌ کد های پروژه های Real world و حتی پروژه های کوچک تر هم به صورت larg scale در حال استفاده هست .

خب اونا چی هستن ؟ ?

  • ارسال درخواست AJAX با تابع سازنده آبجکت XMLHttpRequest
  • ارسال درخواست های Promise Base

۱ ) ارسال درخواست AJAX با XMLHttpRequest

خب توی مرحله اول ، روش اول رو تست میکنیم ، یعنی XMLHttpRequest !

برای این کار ما باید از این آبجکت یدونه Instance بگیریم و اون رو مثلا توی متغیر request ذخیره کنیم

const request = new XMLHttpRequest();

حالا بعد از این کار باید درخواستمون رو ایجاد کنیم ، داریم که

request.open( &quot METHOD &quot, &quot API &quot );

بجای کلمه METHOD ، متدی که مد نظرمون هست مثلا GET , POST, ... رو قرار میدیم ( فرضا ما الان از GET استفاده میکنیم توی این مثال ) و بجای API هم Endpoint مربوط به همون API که میخوایم باهاش کار کنیم رو ، وارد میکنیم.

مفسر جاواسکریپت ( Javascript ) ، بعد از رد شدن از این خط ، درخواست مارو ایجاد میکنه ولی ارسال ، نه !

برای اینکه درخواستمون رو به سمت سرور ارسال کنه ،‌ از statement زیر استفاده میکنیم

request.send();

حالا درخواست ما ارسال شده ولی ما هنوز به هیچ پاسخ ( Response ) دسترسی نداریم ،‌ برای اینکار باید منتظر یک رویداد ( Event ) باشیم ، به این صورت :

request.addEventListener( &quot load &quot , function () { // The this keyword points to the &quotrequest&quot const [data] = JSON.parse(this.responseText); // Work with data || DOM manipulation .... } );

خب تا اینجا ما AJAX call رو به خوبی انجام دادیم و تا به الان مشکلی نبود ...

مشکل ما از اونجایی شروع میشه که میخوایم درخواست های AJAX متعددی رو به صورت تو در تو ( Nested AJAX calls ) داشته باشیم ،‌ مثلا فرض کنید ما یک سری دیتا رو از API1 گرفتیم و از اونا میخوایم توی درخواستمون به API2 استفاده کنیم ، مثلا ( توصیه میشه کد رو توی ادیتور خودتون کپی کنید تا هم ایندنتیشن ها بهتر رعایت بشه و هم واضح تر ببینید ) :

request.addEventListener( &quot load &quot , function () { // 1st AJAX call const [data] = JSON.parse(this.responseText); // 2nd AJAX call const newRequest = new XMLHttpRequest(); newRequest.open( &quot METHOD &quot, &quot API &quot ); newRequest.send(); request.addEventListener( &quot load &quot , function () { const [data1] = JSON.parse(this.responseText); // Work with data1 || DOM manipulation ..... // Maybe some othe AJAX calls ..... } ); } );

خب این کد هم الان بدون مشکل کار میکنه و ما میتونیم کاملا اونو Handle و مدیریت کنیم .

عه ? ، احمدرضا تو که گفتی این روش مشکل داره ، پس چرا الان میگی همه چیز اوکیه‌؟ ?

خب اره الآن هم سر حرفم هستم ،‌

تصور کنید ، ما اگه که این درخواست های ایجکس رو میخواستیم ۱۰ بار به صورت تو در تو انجام بدیم ، چی میشد ؟

احتمالا درست حدس زده باشید ،‌ ما قرار بود پوستمون کنده بشه و با پدیده ترسناک Callback HELL ( جهنمِ Callback ) رو به رو بشیم ، برای اینکه این مقاله خیلی طولانی نشه اونو جداگانه توضیح میدم و هر وقت اماده شد لینکش رو " اینجا " قرار میدم.

⚠️ نتیجه این بخش ،‌ بخش ۱ از ۳ :‌

این روش یکم قدیمی تر از روش هایی هست که میخوایم بررسی کنیم ،‌ ولی هنوز داره استفاده میشه ، فارغ از این ، مشکل ما باهاش این هست که مارو درگیر CALLBACK HELL میکنه ، که کدمون رو ترسناک میکنه و اصطلاحا Readability کدمون رو بسیار پایین میاره (‌ خصوصا در Nested AJAX call ها ) که قطعا ما اینو نمیخوایم !



۲) ارسال درخواست های AJAX به صورت Promise Base

این درخواست ها خودشون به خودی خود ، دو دسته ( یا بهتره بگیم دو روش ) هستند :

  • ارسال درخواست AJAX با استفاده از fetch
  • ارسال درخواست AJAX با استفاده از توابع async و دریافت داده با await


? پس بریم که به ترتیب بشکافیمشون ?

۲ -> ۱ ) استفاده از تابع fetch

برای ارسال درخواست به سرور ، توی این روش ، داریم که :

// You will definitely be able to wrap all of the upcoming code inside a function fetch( &quot API &quot , { &quotOptions&quot } );

اولین چیزی که به تابع پاس میدیم ، Endpoint هست که همون API میشه و به عنوان پارامتر دوم ، یدونه آبجکت از آپشن ها رو میدیم، اگه که ما کلا از پارامتر دوم صرف نظر کنیم ، انگار که از متد GET استفاده کردیم ،‌ ولی اگه که بخوایم اون رو کاستومایز کنیم اون آبجکت مربوط به پارامتر دوم ،‌ باید اینجوری باشه :

... ,{ method: 'POST', // *GET, POST, PUT, DELETE, etc. mode: 'cors', // no-cors, *cors, same-origin cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached credentials: 'same-origin', // include, *same-origin, omit headers: { 'Content-Type': 'application/json' // 'Content-Type': 'application/x-www-form-urlencoded', }, ...

***‌ ⚠️ دقت کنید که این تابع میتونه پارامتر های دیگه ای هم داشته باشه ، ولی این آبجکت ، پارامتر دومش هست و اگه میخواید چیزی رو از سرور بگیرید ،‌ احتیاجی به پاس دادنش به تابع fetch ندارید ! ⚠️ ***

الان درخواستمون ارسال شد اما چیزی دست ما نرسیده ، خب چیکارش کنیم‌؟

برای این کار باید درواقع Promise رو Consume کنیم ، اینجوری :

fetch( &quot https://something.somewhere/somedirectiory/ &quot ) .then( resp => resp.json() /* &quot.json()&quot method is available for all Promises */ ) .then( data => { // Some sort of functionalities ... } ) ;

به همین زیبایی ? ، و نکته حائز اهمیت اینجاست که اگه ما Nested AJAX call هم داشته باشیم ( دو تا سه تا نه ها‌!!! تو بگو هزار تا ) دیگه ما مشکل Callback Hell رو نداریم ? ،‌ ببینید :

fetch( &quot https://something.somewhere/somedirectiory/ &quot ) .then( resp => resp.json() /* &quot.json()&quot method is available for all Promises */ ) .then( data => { // Some sort of functionalities ... ( working with data ) return fetch( &quot NEW API &quot ); } ) ;

و فقط کافیه که اون AJAX call جدید رو توی then مربوط به Handle کردن data بیاریم و return کنیم ? ، به همین سادگی !!!

⚠️⚠️ --> این روش برای ما خوبه چون که مارو از شر Callback Hell خلاص میکنه ،‌ ولی خیلیا حواسشون نیست و خودشونو با اون دوباره درگیر میکنن ( با جهنم کالبک ) و به دام میوفتن ! ، به همین منظور روش درست که باعث رهایی از این دام میشه رو توی بلاک کد زیر با ✅ و روشی که مارو نابود میکنه با ❌ نشون خواهم داد ( باز هم توصیه میکنم که کد رو توی کد ادیتور خودتون کپی کنید و بررسی کنید ) !

// ❌ WRONG way ❌ fetch( &quot https://something.somewhere/somedirectiory/ &quot ) .then( resp => resp.json() ) .then( data => { // Some sort of functionalities ... ( working with data ) // ⚠️ Watch the following code, carefully ⚠️ return fetch( &quot NEW API &quot ).then( res => res.json() ).then( data => /* DATA */ ); } ) ; /* --------------------------------------------- Seprator ------------------------------------------------- */ // ✅ CORRECT way ✅ fetch( &quot https://something.somewhere/somedirectiory/ &quot ) .then( resp => resp.json() ) .then( data => { // Some sort of functionalities ... ( working with data ) return fetch( &quot NEW API &quot ) // RETURN } ) .then( res => res.json() ) .then( data => /* DATA */ );

⚠️ نتیجه این بخش ،‌ بخش۲ از ۳ :‌

این روش به مراتب بهتر از روشی هست که توی بخش ۱ از ۳ بررسی کردیم ،‌ اما هنوز یکم مشکل داره ولی خیلی استفاده میشه و خیلی هم تمیز تر از قبلی هست ولی مشکلش چیه ؟ قهوه‌ت سرد نشه ? ، مشکلش اینه که درسته ما ٰCallback Hell نداریم ، ولی همونطور که میبینید ،‌ ما هنوز کالبک های معمولی رو داریم و کالبک هم یعنی کلی پرانتز و نقطه و غیره که باز باعث سردرگمی ما بشه ، که ما باز هم اینو نمیخوایم!


۲ -> ۲ ) استفاده از توابع Async ( به همراه await برای دریافت دیتا )

خب رسیدیم به اخرین روش و مهمترین‌شون ? !

در واقع ما توی این روش از همون کانسپت های روش معرفی شده توی بخش ۲ از ۳ استفاده میکنیم ، ولی به نوعی که نه تنها جهنم کالبک ،‌ بلکه خود کالبک معمولی رو هم نداشته باشیم !

چه چیزی از این بهتر میتونه باشه که ما به درستی AJAX call رو انجام بدیم ، از شر کالبک و جهنم کالبک راحت بشیم و دیگه عملا پرانتز و chain کردن کلی متد مرتبط با Promise ها مثل then رو نداشته باشیم و از اونا فقط به صورت flat استفاده کنیم ? ؟

بریم که داشته باشیم :

// Using Asynchronous function + function expression const someName = async function ( /* maybe an argument */ ) { // 1st AJAX call const res = await fetch( &quot https://something.somewhere/somedirectiory/ &quot ); const data = await res.json(); .... // 2nd AJAX call const res2 = await fetch( &quot https://something2.somewhere/somedirectiory/ &quot ); const data2= await res2.json(); .... // Nth AJAX call .... }; someName();

و تمام ! ?

همونطوری که توی بلاک کد بالا میبینید ،‌ نه خبری از callback هست نه جهنمش ( ? ) و نه متد then هست و نه هیچ چیز اضافه ای !

مثل کد های sync که توی حالت معمول داریم ، این ها هم خط به خط و استیتمنت به استیتمنت نوشته شدن و رفتن پی کارشون و البته که مارو به هدفمون یعنی AJAX call رسوندن !

فکر میکنید قهرمان‌مون کی هست ? ؟

⚠️ نتیجه نهایی این مقاله ،‌ بخش۳ از ۳ ( آخر) :‌

این روش ( توابع async ) خیلی خیلی بهتر از روشی هست که توی بخش ۱ از ۳ بررسی کردیم ،‌ چرا که اینجا دیگه Callback Hell نداریم و همینطور از روش بررسی شده در بخش ۲ از ۳ خیلی بهتر هست به این دلیل که اصلا Callback نداریم ? !

این روش صرفا خط به خط کد هامون زیر هم هستن و کاملا Clean ، به روز و خوانا هست !

پس این روش همون روش قهرمان ماست ✅? !




خب این مقاله به پایان رسید ،‌ دمتون خیلی گرم که وقت با ارزشتون رو گذاشتین و این مقاله رو مطالعه کردید

موضوع پیشنهادی و یا انتقادی از مقاله اگه داشتین با کمال میل در بخش مربوط به کامنت این مقاله یا ایمیلم درخدمتم

اگه که براتون مفید واقع شد ممنون میشم که این مقاله رو لایک کنید و بعد بین دوستاتون اشتراک بدین ?


جاوااسکریپتajax
من احمدرضا مظفری به عنوان Software developer توی شرکت همکاران سیستم مشغول هستم ، توی زمینه وب ، میخونم ، یادمیگیرم ، مینویسم .
شاید از این پست‌ها خوشتان بیاید