مقدمه‌ای بر fetch()‎

fetch() به شما امکان می‌دهد درخواست‌های شبکه مشابه XMLHttpRequest (XHR) ایجاد کنید. تفاوت اصلی این است که Fetch API از Promises استفاده می‌کند که API ساده‌تری دارد تا به شما کمک کند از callbackهای پیچیده در XMLHttpRequest API اجتناب کنید.

Browser Support

  • Chrome: 42.
  • Edge: 14.
  • Firefox: 39.
  • Safari: 10.1.

Source

اگر قبلاً از Promises استفاده نکرده‌اید، مقدمه‌ای بر JavaScript Promises را بررسی کنید.

درخواست واکشی پایه

در اینجا مثالی از پیاده‌سازی با XMLHttpRequest و سپس با fetch آورده شده است. می‌خواهیم نشانی وبی را درخواست کنیم، پاسخی دریافت کنیم، و آن را به‌عنوان JSON تجزیه کنیم.

XMLHttpRequest

XMLHttpRequest به دو شنونده نیاز دارد تا موارد موفقیت و خطا را مدیریت کند، و یک فراخوانی به open() و send(). نمونه‌ای از اسناد MDN.

function reqListener () {
  const data = JSON.parse(this.responseText);
  console.log(data);
}

function reqError (err) {
  console.log('Fetch Error :-S', err);
}

const oReq = new XMLHttpRequest();
oReq.onload = reqListener;
oReq.onerror = reqError;
oReq.open('get', './api/some.json', true);
oReq.send();

واکشی کردن

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

fetch('./api/some.json')
  .then(response => {
    if (response.status !== 200) {
      console.log(`Looks like there was a problem. Status Code: ${response.status}`);

      return;
    }

    // Examine the text in the response
    response.json().then(function(data) {
      console.log(data);
    });
  })
  .catch(err => {
    console.log('Fetch Error :-S', err);
  });

درخواست fetch() برای انجام همان کار مثال XHR فقط به یک فراخوانی نیاز دارد. برای پردازش پاسخ، ابتدا بررسی می‌کنیم که وضعیت پاسخ ‎200 باشد، سپس پاسخ را به‌صورت JSON تجزیه می‌کنیم. پاسخ به درخواست fetch() یک شیء جاری‌سازی است، یعنی پس‌از اینکه روش json() را فراخوانی کردیم، یک Promise برگردانده می‌شود. جاری‌سازی به‌صورت ناهمگام انجام می‌شود.

فراداده پاسخ

مثال قبلی وضعیت شیء پاسخ و نحوه تجزیه پاسخ به‌عنوان JSON را نشان داد. در اینجا نحوه مدیریت سایر فراداده‌هایی که ممکن است بخواهید به آن‌ها دسترسی داشته باشید، مانند سرصفحه‌ها، آورده شده است:

fetch('users.json').then(response => {
  console.log(response.headers.get('Content-Type'));
  console.log(response.headers.get('Date'));

  console.log(response.status);
  console.log(response.statusText);
  console.log(response.type);
  console.log(response.url);
});

انواع پاسخ

وقتی درخواست واکشی می‌کنیم، پاسخ با یکی از این موارد ارائه می‌شود:response.type «basic»، «cors»، یا «opaque». این types نشان می‌دهد که منبع از کجا آمده است و می‌توانید از آن‌ها برای تعیین نحوه برخورد با شیء پاسخ استفاده کنید.

وقتی مرورگر منبعی را در همان مبدأ درخواست می‌کند، پاسخ دارای نوع basic است و محدودیت‌هایی برای آنچه می‌توانید از پاسخ مشاهده کنید وجود دارد.

اگر درخواستی برای منبعی در مبدأ دیگری ایجاد شود و آن مبدأ سرصفحه‌های COR را برگرداند، نوع آن cors است. پاسخ‌های cors مشابه پاسخ‌های basic است، اما سرصفحه‌هایی را که می‌توانید مشاهده کنید به Cache-Control،‏ Content-Language،‏ Content-Type،‏ Expires، Last-Modified، و Pragma محدود می‌کند.

پاسخ‌های opaque از مبدأ دیگری می‌آیند که سرصفحه‌های CORS را برنمی‌گرداند. با پاسخ مبهم نمی‌توانیم داده‌های برگردانده‌شده را بخوانیم یا وضعیت درخواست را مشاهده کنیم، یعنی نمی‌توانید بررسی کنید که درخواست موفقیت‌آمیز بوده است یا نه.

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

  • same-origin فقط برای درخواست‌های دارایی‌های موجود در همان مبدأ موفق می‌شود و همه درخواست‌های دیگر را رد می‌کند.
  • cors درخواست‌های دارایی‌ها را در همان مبدأ و مبدأهای دیگری که سرایندهای COR مناسب را برمی‌گردانند مجاز می‌کند.
  • cors-with-forced-preflight پیش‌از ایجاد هرگونه درخواست، بررسی پیش‌پرواز انجام می‌دهد.
  • no-cors برای درخواست از مبدأهای دیگری که سرصفحه CORS ندارند و منجر به پاسخ opaque می‌شوند درنظر گرفته شده است، اما همان‌طور که گفته شد، این کار درحال‌حاضر در محدوده سراسری پنجره امکان‌پذیر نیست.

برای تعریف حالت، یک شیء گزینه‌ها را به‌عنوان پارامتر دوم در درخواست fetch اضافه کنید و حالت را در آن شیء تعریف کنید:

fetch('http://some-site.com/cors-enabled/some.json', {mode: 'cors'})
  .then(response => response.text())
  .then(text => {
    console.log('Request successful', text);
  })
  .catch(error => {
    log('Request failed', error)
  });

زنجیره‌سازی Promise

یکی از ویژگی‌های عالی وعده‌ها، توانایی زنجیر کردن آن‌ها به یکدیگر است. برای fetch()، این به شما امکان می‌دهد منطق را در درخواست‌های واکشی هم‌رسانی کنید.

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

function status (response) {
  if (response.status >= 200 && response.status < 300) {
    return Promise.resolve(response)
  } else {
    return Promise.reject(new Error(response.statusText))
  }
}

function json (response) {
  return response.json()
}

fetch('users.json')
  .then(status)
  .then(json)
  .then(data => {
    console.log('Request succeeded with JSON response', data);
  }).catch(error => {
    console.log('Request failed', error);
  });

این مثال تابع status را تعریف می‌کند که response.status را بررسی می‌کند و یا Promise حل‌شده را به‌عنوان Promise.resolve() برمی‌گرداند، یا Promise ردشده را به‌عنوان Promise.reject() برمی‌گرداند. این اولین روشی است که در زنجیره fetch() فراخوانی می‌شود.

اگر Promise حل‌وفصل شود، دستورگان سپس متد json() را فراخوانی می‌کند که یک Promise دوم را از فراخوانی response.json() برمی‌گرداند و شیء حاوی JSON تجزیه‌شده را ایجاد می‌کند. اگر تجزیه ناموفق باشد، Promise رد می‌شود و عبارت catch اجرا می‌شود.

این ساختار به شما امکان می‌دهد منطق را در همه درخواست‌های واکشی هم‌رسانی کنید، که باعث می‌شود کد راحت‌تر نگهداری، خوانده، و آزمایش شود.

درخواست پست

گاهی اوقات برنامه وب باید میانای برنامه‌سازی کاربردی را با روش POST فراخوانی کند و برخی پارامترها را در بدنه درخواست بگنجاند. برای انجام این کار، پارامترهای method و body را در گزینه‌های fetch() تنظیم کنید:

fetch(url, {
    method: 'post',
    headers: {
      "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
    },
    body: 'foo=bar&lorem=ipsum'
  })
  .then(json)
  .then(data => {
    console.log('Request succeeded with JSON response', data);
  })
  .catch(error => {
    console.log('Request failed', error);
  });

ارسال اعتبارنامه‌ها با درخواست واکشی

برای ایجاد درخواست واکشی با اطلاعات اعتباری مانند کوکی‌ها، مقدار credentials درخواست را روی "include" تنظیم کنید:

fetch(url, {
  credentials: 'include'
})