MATIN MOLKARA
SERIES: JavaScript — PART 52 OF 108

52- آموزش جاوااسکریپت | پروژه عملی : قسمت 1 از 2- ساخت کتابخانه اختصاصی AJAX (EasyHTTP)

در این آموزش، فرآیند ساخت یک کتابخانه اختصاصی AJAX به نام EasyHTTP را با استفاده از پروتوتایپ‌های جاوااسکریپت (ES5) آغاز می‌کنیم. هدف ما ساده‌سازی درخواست‌های HTTP، مدیریت بهتر پاسخ‌های سرور و کنترل عملیات غیرهمزمان با استفاده از Callbackها است.

در این آموزش می‌خواهیم یک کتابخانه‌ی اختصاصی برای ارسال درخواست‌های AJAX بسازیم که اسمش را EasyHTTP می‌گذاریم.
هدف ما این است که به‌جای نوشتن کدهای تکراری XMLHttpRequest در هر قسمت از پروژه، یک ابزار ساده و قابل استفاده دوباره بسازیم که بتواند درخواست‌های زیر را مدیریت کند:

  • GET
  • POST
  • PUT
  • DELETE

1) انتخاب یک API برای تست

برای اینکه کتابخانه‌ی خودمان را تست کنیم، به یک API واقعی اما آزمایشی نیاز داریم.
در این ویدیو از JSONPlaceholder استفاده می‌کنیم.

JSONPlaceholder یک REST API جعلی و رایگان است که برای تست و پروتوتایپ‌سازی طراحی شده.
این سرویس منابع مختلفی دارد، مثل:

  • posts
  • comments
  • users

ما در این آموزش با posts کار می‌کنیم.


2) بررسی endpointها

وقتی وارد JSONPlaceholder می‌شویم، برای هر منبع یک سری endpoint داریم.

مثلاً برای posts:

  • GET /posts → دریافت همه‌ی پست‌ها
  • GET /posts/1 → دریافت یک پست خاص
  • POST /posts → ساخت پست جدید
  • PUT /posts/1 → ویرایش پست
  • DELETE /posts/1 → حذف پست

نکته مهم این است که این API یک API واقعی برای ذخیره‌سازی دائمی نیست.
یعنی اگر پستی ارسال کنیم، واقعاً روی سرور آنها ذخیره نمی‌شود، اما یک پاسخ موفق برمی‌گرداند تا ما بتوانیم در برنامه‌ی خودمان آن را ببینیم و تست کنیم.


3) ساخت فایل‌های پروژه

برای این پروژه یک پوشه جدید به نام easyhttp می‌سازیم و آن را در VS Code باز می‌کنیم.

داخل پروژه، سه فایل می‌سازیم:

  1. index.html
  2. easyhttp.js
  3. app.js

4) آماده‌سازی فایل HTML

در فایل index.html یک ساختار ساده‌ی HTML می‌نویسیم.
در این مثال، همه چیز را فعلاً از طریق console بررسی می‌کنیم، پس فقط یک heading ساده هم کافی است.

نکته‌ی خیلی مهم این است که ترتیب قرار گرفتن فایل‌های JavaScript اهمیت دارد:

  • اول باید easyhttp.js لود شود
  • بعد app.js

چون قرار است در app.js از کتابخانه‌ای استفاده کنیم که در easyhttp.js ساخته‌ایم.


5) ساخت کتابخانه با استفاده از prototype

در فایل easyhttp.js کتابخانه‌ی خودمان را می‌سازیم.

چون این پروژه بر اساس ES5 نوشته می‌شود، به‌جای class از prototype استفاده می‌کنیم.

سازنده‌ی اصلی کتابخانه

function EasyHTTP() {
  this.http = new XMLHttpRequest();
}

در اینجا یک constructor function ساختیم که داخل آن یک نمونه از XMLHttpRequest ذخیره می‌شود.

یعنی هر بار که از EasyHTTP یک نمونه جدید بسازیم، یک http جدید خواهیم داشت.


6) ساخت متد GET

حالا اولین متد کتابخانه را می‌سازیم: get.

EasyHTTP.prototype.get = function(url) {
  this.http.open('GET', url, true);
  this.http.send();
};

اما این فقط شروع کار است.
ما باید پاسخ سرور را هم دریافت کنیم، بنابراین از onload استفاده می‌کنیم.


7) مشکل this داخل onload

اگر کد را این‌طور بنویسیم:

EasyHTTP.prototype.get = function(url) {
  this.http.open('GET', url, true);

  this.http.onload = function() {
    console.log(this.http.status);
  };

  this.http.send();
};

به مشکل برمی‌خوریم.

چرا؟

چون داخل تابع onload، مقدار this دیگر به نمونه‌ی EasyHTTP اشاره نمی‌کند، بلکه به خود XMLHttpRequest اشاره می‌کند.
به همین دلیل this.http در آنجا undefined می‌شود.


8) حل مشکل this با self

برای حل این مشکل در ES5، یک متغیر کمکی می‌سازیم:

var self = this;

یعنی قبل از ورود به تابع داخلی، مقدار this را در self ذخیره می‌کنیم.

نسخه‌ی اصلاح‌شده:

EasyHTTP.prototype.get = function(url) {
  var self = this;

  this.http.open('GET', url, true);

  this.http.onload = function() {
    if (self.http.status === 200) {
      console.log(self.http.responseText);
    }
  };

  this.http.send();
};

حالا self به همان نمونه‌ی اصلی EasyHTTP اشاره می‌کند و می‌توانیم به status و responseText دسترسی داشته باشیم.


9) تست اولیه در app.js

حالا در فایل app.js یک نمونه از کتابخانه می‌سازیم:

const http = new EasyHTTP();

http.get('https://jsonplaceholder.typicode.com/posts');

وقتی این را اجرا کنیم، پاسخ API داخل console نمایش داده می‌شود و ما لیست پست‌ها را دریافت می‌کنیم.


10) چرا return جواب نمی‌دهد؟

ممکن است در این مرحله فکر کنیم که می‌توانیم نتیجه را مستقیم return کنیم، مثلاً:

EasyHTTP.prototype.get = function(url) {
  var self = this;

  this.http.open('GET', url, true);

  this.http.onload = function() {
    if (self.http.status === 200) {
      return self.http.responseText;
    }
  };

  this.http.send();
};

اما این روش کار نمی‌کند.

دلیل:

درخواست‌های AJAX به صورت غیرهمزمان هستند.
یعنی کد return قبل از اینکه پاسخ سرور برسد اجرا می‌شود.
پس نتیجه‌ای که برمی‌گردد undefined خواهد بود.


11) راه‌حل درست: callback

برای حل این مشکل باید از callback استفاده کنیم.

یعنی متد get علاوه بر url یک تابع callback هم بگیرد:

EasyHTTP.prototype.get = function(url, callback) {
  var self = this;

  this.http.open('GET', url, true);

  this.http.onload = function() {
    if (self.http.status === 200) {
      callback(null, self.http.responseText);
    }
  };

  this.http.send();
};

12) استفاده از callback در app.js

حالا در فایل app.js متد get را این‌طور صدا می‌زنیم:

const http = new EasyHTTP();

http.get('https://jsonplaceholder.typicode.com/posts', function(response) {
  console.log(response);
});

اما برای استانداردتر شدن، بهتر است callback دو ورودی داشته باشد:

  • error
  • response

مثلاً:

http.get('https://jsonplaceholder.typicode.com/posts', function(err, posts) {
  if (err) {
    console.log(err);
  } else {
    console.log(posts);
  }
});

13) اضافه کردن error handling

حالا متد get را کمی بهتر می‌کنیم تا اگر پاسخ موفق نبود، خطا هم برگرداند.

EasyHTTP.prototype.get = function(url, callback) {
  var self = this;

  this.http.open('GET', url, true);

  this.http.onload = function() {
    if (self.http.status === 200) {
      callback(null, self.http.responseText);
    } else {
      callback('Error: ' + self.http.status);
    }
  };

  this.http.send();
};

اینجا چه اتفاقی می‌افتد؟

  • اگر وضعیت 200 باشد، خطا null است و داده‌ها در responseText برمی‌گردند.
  • اگر وضعیت موفق نباشد، خطا برمی‌گردد و response ارسال نمی‌شود.

14) تست خطا

اگر آدرس را اشتباه بنویسیم، مثلاً:

http.get('https://jsonplaceholder.typicode.com/posts1', function(err, posts) {
  if (err) {
    console.log(err);
  } else {
    console.log(posts);
  }
});

آنگاه callback خطا را دریافت می‌کند، مثلاً:

Error: 404

15) نتیجه‌ی این مرحله

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

  • ساخت XMLHttpRequest
  • open
  • onload
  • بررسی status
  • دریافت responseText

همه‌ی این‌ها حالا داخل کتابخانه‌ی EasyHTTP مخفی شده‌اند و فقط با یک متد ساده می‌توانیم درخواست GET بفرستیم.


16) قدم بعدی

در مرحله‌ی بعدی، متدهای زیر را هم به کتابخانه اضافه خواهیم کرد:

  • POST
  • PUT
  • DELETE

تا بتوانیم به‌صورت کامل با REST API کار کنیم.

// 0 comments
#JavaScript#JSONPlaceholder#Prototypes#EasyHTTP#Callback Function#HTTP Requests#AJAX#ES5#توسعه وب#آموزش جاوااسکریپت

نظرات (0)

نظر خود را بنویسید