در چند قسمت قبل کتابخانه ی esayHTTP خود را با استفاده از callback ها و توابع قدیمی و AJAX و شیء HXR و prototype و غیره نوشته بودیم اما حالا که با تکنولوژی های جدیدتری مثل Promise ها آشنا هستیم می توانیم آن را به روش بسیار مدرن تری بازنویسی کنیم.
محتویات فایل HTML من به شکل زیر است:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>EasyHTTP2 Example</title> </head> <body> <script src="easyhttp2.js"></script> <script src="app.js"></script> </body> </html>
همانطور که می بینید فایلی به نام easyhttp2.js را درون آن بارگذاری کرده ام که قرار است نسخه ی جدیدی از کتابخانه ی esayHTTP ما باشد بنابراین شما هم فایل های app.js و easyhttp2.js خود را در کنار فایل index.html داشته باشید.
برای شروع وارد فایل easyhttp2.js شوید تا کد نویسی را شروع کنیم. در این نسخه نیازی به constructor و امثال آن نداریم چرا که نیازی به شیء XHR نداریم بنابراین می توانیم مستقیما کلاس esayHTTP و سپس متد get خود را تعریف کنیم:
class EasyHTTP { get (url) { } }
من می خواهم در ابتدای کار بدون استفاده از promise ها این کد را بنویسم تا متوجه نیازمان به آن ها شوید:
class EasyHTTP { get(url) { fetch(url) .then(res => res.json()) .then(data => console.log(data)) .catch(err => console.log(err)); } }
در حال حاضر کد بالا متد fetch از روش Fetch API را صدا می زند و یک url به آن می دهد. از آنجایی که خود fetch یک promise را بر می گرداند می توانیم از then استفاده کنیم و می گوییم res یا response (پاسخ سرور) را دریافت کرده و سپس با یک Then دیگر Data یا داده ها را دریافت می کرده و سپس console.log می کنیم. نهایتا با استفاده از دستور catch خطاهای احتمالی را دریافت کرده و آن ها را نیز console.log می نماییم. کدها را تا اینجای کار ذخیره کرده و به app.js بروید تا آن ها را تست کنیم.
درون app.js ابتدا کتابخانه ی خودمان را initialize می کنیم:
const http = new EasyHTTP;
سپس برای تست کردن آن با استفاده از سرور JSONPlaceholder ده نفر از کاربران (user) را دریافت می کنیم:
const http = new EasyHTTP; // Get Users http.get('https://jsonplaceholder.typicode.com/users');
با ذخیره و اجرای کد بالا در قسمت کنسول مرورگر پاسخ زیر را دریافت می کنیم:
اگر دقت کنید ما این کاربران را مستقیما log کرده ایم:
class EasyHTTP { get(url) { fetch(url) .then(res => res.json()) .then(data => console.log(data)) .catch(err => console.log(err)); } }
یعنی به محض دریافت log می شوند اما چنین حالتی تقریبا در هیچ کتابخانه ای وجود خارجی ندارد چرا که ما در برنامه های واقعی پاسخ های سرور را log نمی کنیم! اگر کد بالا را به شکل صحیح تغییر دهیم تا داده ها را return کند:
class EasyHTTP { get(url) { fetch(url) .then(res => res.json()) .then(data => data) .catch(err => data); } }
و سپس به فایل App.js رفته و کدهایش را به شکل زیر بنویسیم:
const users = http.get('https://jsonplaceholder.typicode.com/users'); console.log(users);
در قسمت کنسول مرورگر با خطای undefined روبرو می شویم چرا؟ به دلیل اینکه کد ما متقارن است و برنامه برای رسیدن پاسخ از سمت سرور صبر نمی کند بلکه سریعا ثابتی به نام users می سازد که درخواست get خود را به آدرسی ارسال کرده و همانجا نتیجه را می خواهد. قطعا رسیدن پاسخ به ما مدتی طول می کشد (حتی اگر به میلی ثانیه باشد) و از آنجایی که برنامه چیزی برای قرار دادن به عنوان مقدار users ندارد، مقدار undefined را قرار خواهد داد.
برای حل این مشکل باید از promise ها استفاده کرده و بگوییم:
class EasyHTTP { // Make an HTTP GET Request get(url) { return new Promise((resolve, reject) => { fetch(url) .then(res => res.json()) .then(data => resolve(data)) .catch(err => reject(err)); }); } }
در واقع تمام کدهایمان را داخل promise قرار داده و مثل همیشه از reject و resove برای تعیین خروجی استفاده کرده ایم. حالا اگر کدها را اجرا کنیم، داده های ارسالی از سرور را نمی گیریم بلکه یک promise با وضعیت pending برایمان ارسال می شود:
چرا؟ به دلیل اینکه ما در فایل app.js فقط درخواست را به سرور ارسال کردیم اما چیزی دریافت نکردیم:
const users = http.get('https://jsonplaceholder.typicode.com/users'); console.log(users);
برای دریافت پاسخ سرور باید از then استفاده کنیم:
// Get Users http.get('https://jsonplaceholder.typicode.com/users') .then(data => console.log(data)) .catch(err => console.log(err)); console.log(users);
حالا با اضافه کردن then داده ها را نیز دریافت می کنیم.
به همین شکل می توانیم درخواست POST خود را نیز بنویسیم:
// Make an HTTP POST Request post(url, data) { return new Promise((resolve, reject) => { fetch(url, { method: 'POST', headers: { 'Content-type': 'application/json' }, body: JSON.stringify(data) }) .then(res => res.json()) .then(data => resolve(data)) .catch(err => reject(err)); }); }
همانطور که می دانید باید اطلاعات ارسالی به سرور مثل header را در قالب یک شیء ارسال کنیم و تفاوت آنچنانی با جلسات قبل ندارد. این کدها را ذخیره کرده و به app.js بروید تا کدها را تست کنیم. ابتدا باید داده های ارسالی خودمان را تعریف کنیم:
// User Data const data = { name: 'John Doe', username: 'johndoe', email: 'jdoe@gmail.com' }
سپس درخواست post خود را با این داده ها ثبت می کنیم:
// User Data const data = { name: 'John Doe', username: 'johndoe', email: 'jdoe@gmail.com' } // Create User http.post('https://jsonplaceholder.typicode.com/users', data) .then(data => console.log(data)) .catch(err => console.log(err));
درخواست put و Delete ما نیز شبیه به همین درخواست قبل خواهد بود و چیز جدیدی برای توضیح ندارند. از طرفی تمام این متدها را در جلسات قبل بررسی کرده ایم بنابراین همه را یکجا در اختیار شما قرار می دهم:
class EasyHTTP { // Make an HTTP GET Request get(url) { return new Promise((resolve, reject) => { fetch(url) .then(res => res.json()) .then(data => resolve(data)) .catch(err => reject(err)); }); } // Make an HTTP POST Request post(url, data) { return new Promise((resolve, reject) => { fetch(url, { method: 'POST', headers: { 'Content-type': 'application/json' }, body: JSON.stringify(data) }) .then(res => res.json()) .then(data => resolve(data)) .catch(err => reject(err)); }); } // Make an HTTP PUT Request put(url, data) { return new Promise((resolve, reject) => { fetch(url, { method: 'PUT', headers: { 'Content-type': 'application/json' }, body: JSON.stringify(data) }) .then(res => res.json()) .then(data => resolve(data)) .catch(err => reject(err)); }); } // Make an HTTP DELETE Request delete(url) { return new Promise((resolve, reject) => { fetch(url, { method: 'DELETE', headers: { 'Content-type': 'application/json' } }) .then(res => res.json()) .then(() => resolve('Resource Deleted...')) .catch(err => reject(err)); }); } }
برای تست کردن این دو متد در فایل app.js نیز می توانید از کد زیر استفاده کنید:
// Update Post http.put('https://jsonplaceholder.typicode.com/users/2', data) .then(data => console.log(data)) .catch(err => console.log(err)); // Delete User http.delete('https://jsonplaceholder.typicode.com/users/2') .then(data => console.log(data)) .catch(err => console.log(err));
در جلسات بعد در رابطه با استاندارد جدیدتر ES7 صحبت خواهیم کرد (مبحث Async و Await) و پس از بررسی آن ها، همین پروژه را با استفاده از ES7 باز نویسی می کنیم.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.