حالا که با مفهوم برنامه نویسی نامتقارن و AJAX آشنا شدیم باید با شیء XMLHttpRequest یا به اختصار XHR به شکل عملی آشنا شویم. برای یادگیری متدهای این شیء و نحوه ی کار آن تصمیم گرفته ام که مسئله را در یک قالب عملی پیاده سازی کنم.
برای خودتان یک پوشه بسازید که حاوی سه فایل زیر باشد:
من محتوای فایل html و فایل متنی را برای شما قرار می دهم تا آن را در فایل های خود کپی کنید. محتوای فایل 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"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.css" /> <title>Ajax Sandbox</title> </head> <body> <div class="container"> <button id="button">Get Data</button> <br><br> <div id="output"></div> </div> <script src="app.js"></script> </body> </html>
همانطور که می بینید یک صفحه ی ساده که فقط یک دکمه را در خود دارد. محتویات فایل data.txt نیز بسیار کوتاه و عبارت زیر است:
Some plain text data
البته شما می توانید هر رشته ی متنی دیگری را که خواستید به جای آن قرار بدهید. نقشه ی ما این است که فایل app.js را طوری بنویسیم که با کلیک روی دکمه ی Get Data درون فایل HTML، رشته ی متنی فایل data.txt درون صفحه نمایش داده شود. قدم اول مثل همیشه ساخت یک event-listener برای این دکمه است:
document.getElementById('button').addEventListener('click', loadData);
یعنی همزمان با کلیک شدن روی دکمه ی ما، تابعی به نام loadData اجرا شود که هنوز آن را تعریف نکرده ایم. برای انجام این کار به روش همیشگی خودمان عمل می کنیم:
function loadData() { }
قدم اول برای کار با شیء XHR ساخت یک نمونه از آن است. بنابراین می گوییم:
function loadData() { // Create an XHR Object const xhr = new XMLHttpRequest(); }
شما می توانید از هر نام دیگری به جای xhr استفاده کنید. این شیء ما مانند همه ی اشیاء دیگر دارای متدها و خصوصیات خاصی است که یکی از آن ها Open نام دارد. در هنگام استفاده از Open باید نوع درخواست خود و url منبع اصلی را ذکر کنیم. منظورم از منبع اصلی هر چیزی است که می خواهیم به آن دسترسی داشته باشیم مثلا یک API یا در مثال خودمان یک فایل متنی به نام data.txt بنابراین می گوییم:
function loadData() { // Create an XHR Object const xhr = new XMLHttpRequest(); // OPEN xhr.open('GET', 'data.txt', true); }
پارامتر اول نوع درخواست ما است که در اینجا ما می خواهیم یک درخواست GET داشته باشیم (درخواست GET یعنی می خواهیم محتوای فایل را بخوانیم نه اینکه چیزی در آن بنویسیم)، پارامتر دوم آدرس منبع یا فایل ما است و پارامتر سوم مشخص می کند که درخواست async (نامتقارن) باشد یا خیر. من true را انتخاب کرده ام که یعنی درخواست از نوع نامتقارن باشد.
در مرحله ی بعد باید کدهای مربوط به متد onload را بنویسیم. این متد می گوید زمانی که درخواست به صورت کامل دریافت شد چه اتفاقی بیفتد. در واقع این متد یک تابع را دریافت می کند که خودمان آن را می نویسیم و سپس پس از پایان درخواست اجرا می شود. البته قبل از اجرای کدها باید یک شرط را بررسی کنیم: آیا HTTP Status برابر با 200 است یا خیر؟ در صفحات وب مسئله ای به نام HTTP Status وجود دارد (به معنی «وضعیت درخواست HTTP») که بر اساس نتیجه ی درخواست ما، کدهای مختلفی را نشان می دهد که مهم ترین آن ها عبارت اند از:
function loadData() { // Create an XHR Object const xhr = new XMLHttpRequest(); // OPEN xhr.open('GET', 'data.txt', true); xhr.onload = function () { if (this.status === 200) { console.log(this.responseText); } } }
همانطور که گفتم به onload یک تابع داده ایم و درون این تابع ابتدا this.status را بررسی کرده ایم (this به شیء XHR اشاره می کند) تا مطمئن شویم درخواست ما موفقیت آمیز بوده است. سپس از یکی از خصوصیت های شیء XHR به نام responseText استفاده کرده ایم که پاسخ درخواست را به شکل متنی در اختیار ما قرار می دهد. در نهایت باید xhr را send کنیم:
function loadData() { // Create an XHR Object const xhr = new XMLHttpRequest(); // OPEN xhr.open('GET', 'data.txt', true); xhr.onload = function () { if (this.status === 200) { console.log(this.responseText); } } xhr.send(); }
حالا اگر فایل app.js را ذخیره کرده باشید (و مثل محتوای HTML ای که به شما داده ام آن را درون تگ های src در index.html قرار داده باشید) با کلیک روی دکمه ی Get Data متن فایل data.txt درون کنسول نمایش داده خواهد شد:
نکته ی بعدی مقادیری در درخواست های AJAX هستند که به readyState معروف اند:
// readyState Values // 0: request not initialized // 1: server connection established // 2: request received // 3: processing request // 4: request finished and response is ready
خصوصیت onload که بالاتر از آن استفاده کردیم معادل عدد 4 است، یعنی پردازش تمام شده و ما پاسخ خود را دریافت کرده ایم.
سوال: تفاوت کدهای HTTP Status و کدهای readyState چیست؟
پاسخ: کدهای HTTP Status سالم بودن یا سالم نبودن درخواست شما را مشخص می کنند. مثلا اگر درخواستی را به آدرس example.com/posts ارسال کردید آیا چنین صفحه ای وجود دارد؟ اگر چنین صفحه ای وجود نداشته باشد یعنی تمام درخواست شما باطل است اما کدهای readyState مراحل درخواست را مشخص می کنند، یعنی درخواست در چه مرحله ای است؟ آیا پردازش شده؟ آیا آماده است؟ بنابراین زمانی که HTTP Status را چک می کنیم میفهمیم که کلیت درخواست ما صحیح است و وقتی readyState را چک کنیم می فهمیم که درخواست ما در چه مرحله ای قرار دارد.
همچنین باید بدانید که onload تقریبا خصوصیت جدیدی است و قبل از آن همه باید کدهایشان را با چک کردن readyState می نوشتند. بگذارید روش قدیمی نوشتن آن را به شما نشان دهم:
xhr.onreadystatechange = function () { if (this.status === 200 && this.readyState === 4) { console.log(this.responseText); } }
onreadystatechange زمانی اجرا می شود که readyState تغییر کند (هر تغییری، مثلا از مرحله ی 1 به 2 یا از 0 به 1 و الی آخر). حالا گفته ایم هر زمان status ما برابر 200 و readyState برابر 4 بود (یعنی نه تنها درخواست صحیح بود بلکه پردازش شده و پاسخ آن نیز آماده بود) کدهای ما را اجرا کن که فقط یک Console.log است. ما درون کنسول مرورگر باز هم همان جواب قبلی با onload را می گیریم:
برای اینکه مراحل readyState را بهتر درک کنید، من برای تک تک مراحل readyState کد console.log می نویسم. یک console.log را زیر دستور open می گذارم:
// OPEN xhr.open('GET', 'data.txt', true); console.log('READYSTATE', xhr.readyState);
خصوصیت readyState مرحله ای که در آن هستید را به شما می دهد. console.log بعدی را در onreadystatechange می گذارم:
xhr.onreadystatechange = function () { console.log('READYSTATE', xhr.readyState); if (this.status === 200 && this.readyState === 4) { console.log(this.responseText); } }
حالا اگر کنسول مرورگر را نگاه کنیم:
در واقع Open ما را در مرحله ی 1 می گذارد و onreadystatechange از 2 به 3 و سپس به 4 می رود (تمام این مراحل در خودش انجام می شوند). من onreadystatechange را کامنت می کنم و onload را از حالت کامنت خارج می کنم. سپس یک Console.log را نیز برای آن قرار می دهم:
function loadData() { // Create an XHR Object const xhr = new XMLHttpRequest(); // OPEN xhr.open('GET', 'data.txt', true); console.log('READYSTATE', xhr.readyState); xhr.onload = function () { console.log('READYSTATE', xhr.readyState); if (this.status === 200) { console.log(this.responseText); } } // xhr.onreadystatechange = function() { // console.log('READYSTATE', xhr.readyState); // if(this.status === 200 && this.readyState === 4){ // console.log(this.responseText); // } // } xhr.send(); }
حالا اگر به کنسول مرورگر نگاه کنیم می بینیم که فقط مراحل 1 و 4 را داریم. مرحله ی 1 از Open می آید و onload نیز فقط در مرحله ی 4 کار می کند بنابراین نیازی به چک کردن آن نداریم:
متد دیگری نیز داریم که onprogress نام دارد و معادل مرحله ی 3 است (یعنی در حال پردازش درخواست):
// Optional - Used for spinners/loaders xhr.onprogress = function () { console.log('READYSTATE', xhr.readyState); }
حالا اگر به کنسول مرورگر نگاه کنیم می بینیم که عدد 3 نمایش داده می شود. توجه داشته باشید که این متد معمولا برای نمایش spinner ها و علامت های loading هنگام پردازش درخواست استفاده می شود.
متد دیگری که به نظر من حتما باید از آن استفاده کنید onerror است:
xhr.onerror = function () { console.log('Request error...'); }
این متد هنگام برخورد با خطا اجرا خواهد شد.
حالا می توانیم کد onload را به شکل زیر استفاده کنیم:
xhr.onload = function () { console.log('READYSTATE', xhr.readyState); if (this.status === 200) { // console.log(this.responseText); document.getElementById('output').innerHTML = `<h1>${this.responseText}</h1>`; } }
اکنون اگر فایل را ذخیره کنید و به مرورگر بروید متوجه خواهید شد که متن some plain text data درون مرورگر به نمایش در می آید.
در قسمت بعد در مورد JSON صحبت می کنیم چرا که حالت فعلی (کار با فایل متنی) فقط برای آموزش است و تقریبا هیچ گاه از آن استفاده نخواهید کرد.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.