جایگزین کردن jQuery با JavaScript خالص - قسمت پنجم - درخواستهای Ajax
نویسنده: وحید نصیری
تاریخ: ۱۳۹۷/۰۵/۱۹ ۱۱:۲۰
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
|
توسط استاندارد جدید Fetch API | توسط XMLHttpRequest استاندارد |
توسط jQuery |
fetch('/my/name').then(function(response) {
if (response.ok) {
return response.text();
}
else {
throw new Error();
}
}).then(
function success(name) {
console.log('my name is ' + name);
},
function failure() {
console.error('Name request failed!');
}
); | var xhr = new XMLHttpRequest();
xhr.open('GET', '/my/name');
xhr.onload = function() {
if (xhr.status >= 400) {
console.error('Name request failed!');
}
else {
console.log('my name is ' + xhr.responseText);
}
};
xhr.onerror = function() {
console.error('Name request failed!');
};
xhr.send(); | $.get('/my/name').then(
function success(name) {
console.log('my name is ' + name);
},
function failure() {
console.error('Name request failed!');
}
); |
| توسط استاندارد جدید Fetch API | توسط XMLHttpRequest استاندارد | توسط jQuery |
fetch('/user/name', {
method: 'POST',
body: 'some data'
}); | var xhr = new XMLHttpRequest();
xhr.open('POST', '/user/name');
xhr.send('some data'); | $.ajax({
method: 'POST',
url: '/user/name',
contentType: 'text/plain',
data: 'some data'
}); |
| توسط استاندارد جدید Fetch API | توسط XMLHttpRequest استاندارد | توسط jQuery |
fetch('/user/1', {
method: 'PUT',
body: //record including new mobile number
}); | var xhr = new XMLHttpRequest();
xhr.open('PUT', '/user/1');
xhr.send(/* record including new data */); | $.ajax({
method: 'PUT',
url: '/user/1',
contentType: 'text/plain',
data: //record including new data
}); |
| توسط استاندارد جدید Fetch API | توسط XMLHttpRequest استاندارد | توسط jQuery |
fetch('/user/1', {method: 'DELETE'}); | var xhr = new XMLHttpRequest();
xhr.open('DELETE', '/user/1');
xhr.send(); | $.ajax('/user/1', {method: 'DELETE'}); |
$.param({
key1: 'some value',
'key 2': 'another value'
}); key1=some+value&key+2=another+value
$.ajax({
method: 'POST',
url: '/user',
data: {
name: 'VahidN',
address: 'Address 1',
phone: '555-555-5555'
}
}); var xhr = new XMLHttpRequest();
var data = encodeURI('name=VahidN&address=Address 1&phone=555-555-5555');
xhr.open('POST', '/user');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(data); var data = encodeURI('name=VahidN&address=Address 1&phone=555-555-5555');
fetch('/user', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: data
}); function param(object) {
var encodedString = '';
for (var prop in object) {
if (object.hasOwnProperty(prop)) {
if (encodedString.length > 0) {
encodedString += '&';
}
encodedString += encodeURI(prop + '=' + object[prop]);
}
}
return encodedString;
} $.ajax({
method: 'POST',
url: '/user',
contentType: 'application/json',
data: JSON.stringify({
name: 'VahidN',
address: 'Address 1',
phone: {
home: '555-555-5555',
mobile: '444-444-4444'
}
});
}); var xhr = new XMLHttpRequest();
var data = JSON.stringify({
name: 'VahidN',
address: 'Address 1',
phone: {
home: '555-555-5555',
mobile: '444-444-4444'
}
});
xhr.open('POST', '/user');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(data); var xhr = new XMLHttpRequest();
xhr.open('GET', '/user/1');
xhr.onload = function() {
var user = JSON.parse(xhr.responseText);
// do something with this user JavaScript object
};
xhr.send(); fetch('/user', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'VahidN',
address: 'Address 1',
phone: {
home: '555-555-5555',
mobile: '444-444-4444'
}
});
}); fetch('/user/1').then(function(response) {
return response.json();
}).then(function(userRecord) {
// do something with this user JavaScript object
}); fetch('/user/1')
.then(response => response.json()) // Transform the data into json
.then(userRecord => {
// do something with this userRecord object
}); <form action="my/server" method="POST" enctype="multipart/form-data"> <label>First Name: <input name="first"> </label> <label>Last Name: <input name="last"> </label> <button>Submit</button> </form>
-----------------------------1686536745986416462127721994 Content-Disposition: form-data; name="first" Vahid -----------------------------1686536745986416462127721994 Content-Disposition: form-data; name="last" N -----------------------------1686536745986416462127721994--
var formData = new FormData();
formData.append('name', 'VahidN');
formData.append('address', 'Address 1');
formData.append('phone', '555-555-5555');
$.ajax({
method: 'POST',
url: '/user',
contentType: false,
processData: false,
data: formData
}); multipart/form-data; boundary=—————————1686536745986416462127721994
| توسط استاندارد جدید Fetch API | توسط XMLHttpRequest استاندارد |
var formData = new FormData();
formData.append('name', 'VahidN');
formData.append('address', 'Address 1');
formData.append('phone', '555-555-5555');
fetch('/user', {
method: 'POST',
body: formData
}); | var formData = new FormData(),
xhr = new XMLHttpRequest();
formData.append('name', 'VahidN');
formData.append('address', 'Address 1');
formData.append('phone', '555-555-5555');
xhr.open('POST', '/user');
xhr.send(formData); |
| توسط استاندارد جدید Fetch API | توسط XMLHttpRequest استاندارد | توسط jQuery |
var file = document.querySelector(
'INPUT[type="file"]').files[0];
fetch('/uploads', {
method: 'POST',
body: file
});
} | var file = document.querySelector(
'INPUT[type="file"]').files[0],
xhr = new XMLHttpRequest();
xhr.open('POST', '/uploads');
xhr.send(file); | var file = $('INPUT[type="file"]')[0].files[0];
$.ajax({
method: 'POST',
url: '/uploads',
contentType: false,
processData: false,
data: file
}); |
fetch(url)
.then((resp) => resp.json()) // Transform the data into json
.then(function(data) {
// use data object
})
}) function downloadBlob()
{
fetch('/Home/InMemoryReport')
.then(function(response) {
return response.blob();
})
.then(function(xlsxBlob) {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
let url = window.URL.createObjectURL(xlsxBlob);
a.href = url;
a.download = "report.xlsx";
a.click();
window.URL.revokeObjectURL(url);
});
} $.ajax('http://jsonp-aware-endpoint.com/user/1', {
jsonp: 'callback',
dataType: 'jsonp'
}).then(function(response) {
// handle user info from server
}); window.myJsonpCallback = function(data) {
// handle user info from server
};
var scriptEl = document.createElement('script');
scriptEl.setAttribute('src',
'http://jsonp-aware-endpoint.com/user/1?callback=myJsonpCallback');
document.body.appendChild(scriptEl); | توسط استاندارد جدید Fetch API | توسط XMLHttpRequest استاندارد | توسط jQuery |
fetch('http://someotherdomain.com', {
method: 'POST',
headers: {
'Content-Type': 'text/plain'
},
credentials: 'include'
}); | var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://someotherdomain.com');
xhr.withCredentials = true;
xhr.setRequestHeader('Content-Type', 'text/plain');
xhr.send('sometext'); | $.ajax('http://someotherdomain.com', {
method: 'POST',
contentType: 'text/plain',
data: 'sometext',
beforeSend: function(xmlHttpRequest) {
xmlHttpRequest.withCredentials = true;
}
}); |
یک نکتهی تکمیلی: روش لغو صف درخواستهای مکرر fetch ارسالی به سمت سرور
ورودی جستجوی بالای صفحه را درنظر بگیرید که بهازای هربار ورود حرفی، یک درخواست fetch جدید را به سمت سرور ارسال میکند تا نتایج جستجوی حاصل را دریافت کند. مشکل اینجاست که ما تنها به آخرین درخواست fetch ارسال شدهی به سمت سرور نیاز داریم و نه به تمام درخواستهای دیگری که صادر شدهاند. به همین جهت این صف درخواستهای fetch قبلی، غیربهینه بوده و ترافیک بالایی را سبب میشوند. یک روش مواجه شدن با این مساله، استفاده از مفهومی به نام debounce است که در پشت صحنه، از یک تایمر استفاده میکند و فقط هر چند ثانیه یکبار، یک درخواست جدید را به همراه آخرین متن ورودی، به سمت سرور ارسال خواهد کرد. راه دیگری هم برای مواجه شدن با این مشکل، در مرورگرهای جدید پیشبینی شدهاست که AbortController نام دارد. با استفاده از آن میتوان «سیگنالی» را به صف درخواستهای پرتعداد fetch قبلی حاصل از ورود اطلاعات کاربر ارسال کنیم که ... «لغو شوید» و به سمت سرور ارسال نشوید.
برای توضیح بهتر آن، به مثال زیر دقت کنید:
<!DOCTYPE html>
<html>
<body>
<input id="search" type="number" />
<script>
const results = [];
const search = document.getElementById("search");
let controller = new AbortController();
let signal = controller.signal;
const onChange = () => {
const value = search.value;
if (value) {
controller.abort();
controller = new AbortController();
signal = controller.signal;
getPost(value, signal);
}
};
search.onkeyup = onChange;
</script>
</body>
</html>- در اینجا یک input box را داریم که ابتدا، یافت شده و سپس به رخداد onkeyup آن، متد onChange نسبت داده شدهاست تا هربار که کاربر، اطلاعاتی را وارد میکند، فراخوانی شود.
- در ابتدای اسکریپت هم نحوهی نمونه سازی شیء استاندارد جاوااسکریپتی AbortController و دسترسی به شیء signal آنرا مشاهده میکنید.
- در متد onChange، ابتدا مقدار جدید ورودی کاربر، دریافت میشود، سپس این AbortController، لغو میشود و بعد یک نمونهی جدید از آن ایجاد شده و مجددا به شیء signal آن دسترسی پیدا میکنیم تا آنرا به متد getPost ارسال کنیم. این متد هم چنین پیاده سازی را دارد:
const getPost = (value, signal) => {
fetch(
`https://site.com/search/${value}`,
{ signal }
);
};همانطور که مشاهده میکنید، تابع fetch، قابلیت پذیرش شیء signal را هم دارد. زمانیکه با هربار تایپ کاربر، متد ()controller.abort فراخوانی میشود، سیگنالی را به fetch «قبلی» متصل به آن ارسال میکند که ... دیگر به سمت سرور ارسال نشو و متوقف شو. با اینکار فقط آخرین ورودی کاربر، سبب بروز یک fetch موفق میشود و ترافیک ارسالی به سمت سرور کاهش پیدا میکند (چون تمام fetchهای قبلی، سیگنال abort را دریافت کردهاند)؛ مانند مثال زیر که کاربر، 5 بار حروفی را وارد کرده و به ازای هربار ورود حرفی، یک درخواست fetch جدید، ایجاد شده، اما ... فقط آخرین درخواست ارسالی او موفق بوده و نتیجهای را بازگشت داده و مابقی درخواستها ... abort شدهاند. این عملیات abort، در سمت کاربر اعمال میشود؛ یعنی اصلا درخواستی به سمت سرور ارسال نمیشود و این لغو درخواست، توسط برنامهی سمت سرور انجام نشدهاست.