جاوا اسکریپت Async: نسخه ی دوم کتابخانه ی esayHTTP

جاوا اسکریپت Async: نسخه ی دوم کتابخانه ی esayHTTP

جاوا اسکریپت Async: نسخه ی دوم کتابخانه ی esayHTTP

در چند قسمت قبل کتابخانه ی 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');

با ذخیره و اجرای کد بالا در قسمت کنسول مرورگر پاسخ زیر را دریافت می کنیم:

پاسخ دریافتی از JSONPlaceholder
پاسخ دریافتی از JSONPlaceholder

اگر دقت کنید ما این کاربران را مستقیما 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 برایمان ارسال می شود:

وضعیت pending برای promise برگردانده شده
وضعیت pending برای promise برگردانده شده

چرا؟ به دلیل اینکه ما در فایل 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));
پاسخ سرور برای درخواست POST ما
پاسخ سرور برای درخواست POST ما

درخواست های PUT و DELETE

درخواست 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 باز نویسی می کنیم.

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

دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.