AJAX

AJAX (асинхронный JavaScript и XML) — это средство загрузки данных с сервера без перезагрузки страницы. Он использует функциональность встроенного в браузер XMLHttpRequest (XHR), чтобы сделать запрос к серверу, а затем обработать полученные от сервера данные.

jQuery предлагает метод $.ajax и несколько удобных методов чтобы упростить работу с XHR во всех браузерах.

$.ajax

Мы можем использовать метод $.ajax() несколькими путями: можем передать объект конфигурации в качестве единственного аргумента или можем передать адрес и необязательный объект конфигурации. Давайте посмотрим в первом приближении:

// Создаём функцию «обработчика» которая вызывается, когда...

// ...запрос AJAX успешен
var updatePage = function( resp ) {
  $( '#target').html( resp.people[0].name );
};
  
// ...запрос AJAX провалился
var printError = function( req, status, err ) {
  console.log( 'что-то пошло не так', status, err );
};

// Создаём объект для описания запроса AJAX
var ajaxOptions = {
  url: '/data/people.json',
  dataType: 'json',
  success: updatePage,
  error: printError
};

// Инициализируем запрос!
$.ajax(ajaxOptions);

Конечно, вы можете быть менее многословны, просто передавая литеральный объект в метод $.ajax() и применяя анонимные функции для success и error. Такая версия проще для написания и её, вероятно, проще поддерживать:

$.ajax({
  url: '/data/people.json',
  dataType: 'json',
  success: function( resp ) {
    $( '#target').html( resp.people[0].name );
  },
  error: function( req, status, err ) {
    console.log( 'что-то пошло не так', status, err );
  }
});

Как упоминалось ранее, вы можете вызвать метод $.ajax(), передавая ему адрес и необязательный объект конфигурации. Это может быть полезно, если вы хотите использовать конфигурацию по умолчанию для $.ajax() или если вы желаете использовать ту же конфигурацию для нескольких адресов.

$.ajax( '/data/people.json', {
  type: 'GET',
  dataType: 'json',
  success: function( resp ) {
    console.log( resp.people );
  },
  error: function( req, status, err ) {
    console.log( 'что-то пошло не так', status, err );
  }
});

В этой версии обязателен только адрес, но объект конфигурации позволяет нам сказать jQuery какие данные мы хотим передать, какой использовать метод HTTP (GET, POST и др.), какие данные мы ожидаем получить, как реагировать когда запрос успешен или нет и многое другое.

Смотрите документацию по $.ajax() для получения полного списка параметров конфигурации.

А — это асинхронный

Запросы AJAX выполняются асинхронно — это означает, что метод $.ajax возвращает значение до завершения запроса и, следовательно, до выполнения функции success. Это означает, что оператор return данной функции выполнится до полного завершения запроса. Это означает, что функция getSomeData из примера ниже вернёт data до её определения, в результате чего код выдаст ошибку.

Внимание! Некорректный код

var getSomeData = function() {
  var data;
  
  $.ajax({
    url: '/data/people.json',
    dataType: 'json',
    success: function(resp) {
      data = resp.people;
    }
  });

  return data;
}
  
$( '#target' ).html( getSomeData().people[0].name );

Х — это JSON

Термин AJAX был придуман в 2005 году для описания метода извлечения данных с сервера без необходимости обновления страницы. Тогда данные, передаваемые сервером были, как правило, в формате XML, но в наши дни большинство современных приложений использует JSON в качестве формата для данных с сервера.

JSON является строковым представлением данных; он выглядит как обычный объект JavaScript, но может быть использован только для представления подмножества данных, из которых состоит обычный объект JavaScript. Например, JSON не может представлять функции или объекты. Вот пример строки JSON, обратите внимание, что все свойства в кавычках:

{ "people" : [
  {
    "name" : "Бен",
    "url" : "http://benalman.com",
    "bio" : "Я делаю превосходные сайты, полезные плагины jQuery и играю фанк. А также руковожу отделом по разработке плагинов в @bocoup."
  },
  {
    "name" : "Ребекка",
    "url" : "http://rmurphey.com",
    "bio" : "Ведущий JS-разработчик в Bocoup."
  },
  {
    "name" : "Джори",
    "url" : "http://joryburson.com",
    "bio" : "Суперэнтузиаст открытого веб-образования @bocoup. Любит искусство, читать и поддельные усы."
  }
] }

Важно помнить, что JSON является строковым представлением объекта — перед работой строка должна быть преобразована в действительный объект JavaScript. Когда вы работаете с ответом JSON в XHR, то jQuery заботится об этой задаче за вас, но важно понимать разницу между JSON-представлением объекта и самим объектом.

Если вам требуется создать строку JSON из объекта JavaScript или разобрать её за пределами jQuery, современные браузеры предлагают методы JSON.stringify() и JSON.parse(). Их функциональность может быть добавлена в старые браузеры с помощью библиотеки json2.js. jQuery также предлагает метод jQuery.parseJSON, который обеспечивает такую же функциональность как JSON.parse() во всех браузерах. Однако в jQuery нет методов соответствующих JSON.stringify().

Удобные методы

Если мы делаем простой запрос и при этом не заботимся об обработке ошибок — jQuery предлагает несколько «удобных методов», которые позволяют нам использовать сокращённый синтаксис. Каждый из этих методов принимает адрес, необязательный объект данных и функцию для обработки успешного запроса.

$.get( '/data/people.html', function( html ){
  $( '#target' ).html( html );
  });
  
$.post( '/data/save', { name: 'Ребекка' }, function( resp ) {
  console.log( resp );
  });

Передача данных и работа с формами

Мы можем отправить данные с нашим запросом, установив свойство data в объекте конфигурации, либо передав объект в качестве второго аргумента в один из удобных методов.

Для запроса GET эти данные будут прикреплены к строке адреса; для запроса POST они будут отправлены в качестве данных формы. jQuery предлагает полезный метод .serialize() для получения данных формы и преобразования их в формат строки запроса (field1name=field1value&field2name=field2value...):

$( 'form' ).submit(function( event ) {
  event.preventDefault();
  
  var form = $( this );
 
  $.ajax({
    type: 'POST',
    url: '/data/save',
    data: form.serialize(),
    dataType: 'json',
    success: function( resp ) {
      console.log( resp );
    }
  });
});

jqXHR

$.ajax() (и связанные с ним удобные методы) возвращает объект jqXHR (jQuery XML HTTP Request), который содержит множество мощных методов. Мы можем сделать запрос через $.ajax(), а затем передать возвращаемый объект jqXHR в переменную.

var req = $.ajax({
  url: '/data/people.json',
  dataType: 'json'
});

Мы можем использовать этот объект, чтобы к запросу прикрепить функции обработчика, даже после завершения запроса. Например, мы можем использовать метод .then() объекта jqXHR, чтобы привязать функции успеха и ошибки. Метод .then() принимает одну или две функции в качестве аргументов — первая функция будет вызываться если запрос успешен, вторая если запрос не удался.

var success = function( resp ) {
  $( '#target' ).append(
    '<p>людей: ' + resp.people.length + '</p>'
  );
  console.log( resp.people );
};
  
var err = function( req, status, err ) {
  $( '#target' ).append( '<p>что-то пошло не так</p>' );
};

req.then( success, err );
  req.then(function() {
  $( '#target' ).append( '<p>сработало</p>' );
});

Мы можем вызывать .then() в запросе сколько угодно раз, они обслуживаются по очереди.

Если мы не хотим прикреплять функции успеха и ошибки одновременно, то можем использовать методы .done() и .fail() для объекта запроса.

req.done( success );
  req.fail( err );

Если мы хотим прикрепить функцию обработчика, которая выполняется при успехе или неудаче, то можем использовать метод .always() для объекта запроса.

req.always(function() {
  $( '#target' )
  .append( '<p>так или иначе, но завершено</p>' );
});

JSONP

Многие разработчики на JavaScript беспокоятся, когда первый раз пытаются использовать $.ajax для извлечения данных с другого домена, а их запрос не удаётся. К примеру, вы можете попробовать получить данные из сторонних API и обнаружить, что запрос постоянно терпит неудачу.

Как оказалось, по соображениям безопасности XHR для других доменов блокируется браузером. Тем не менее, некоторые сторонние API дают ответ в формате JSONP (JSON with Padding), который позволяет использовать данные, даже если они размещены на другом сервере.

JSONP не совсем AJAX — но ближе, чем использование функциональности XHR в браузере, это действительно работает путём вставки тега <script> на странице, которая содержит запрошенные данные. Несмотря на это, jQuery позволяет сделать запрос JSONP с $.ajax(), указав jsonp как dataType в объекте конфигурации.

$.ajax({
  url: '/data/search.jsonp',
  data: { q: 'a' },
  dataType: 'jsonp',
  success: function( resp ) {
    $( '#target' ).html( 'Результаты: ' + resp.results.length );
  }
});

API, которые предлагает JSONP, указывают имя параметра обработчика для использования в строке запроса. Как правило, это имя callback и его же использует jQuery по умолчанию. Тем не менее, вы можете переименовать его, указав свойство jsonp в объекте конфигурации передаваемом в $.ajax().

Вы также можете использовать удобный метод $.getJSON() чтобы сделать запрос JSONP. Если адрес включает callback=? или аналогичное, то jQuery будет рассматривать его в качестве запроса JSONP.

$.getJSON( '/data/search.jsonp?q=a&callback=?',
  function( resp ) {
    $( '#target' ).html( 'Результаты: ' + resp.results.length );
  }
);

CORS (cross-origin resource sharing) — ещё один вариант для междоменных запросов. Однако он не поддерживается в старых браузерах и для работы требуются настройки на стороне сервера и манипуляция с заголовками XHR.

Автор: Ребекка Мёрфи
Последнее изменение: 11.06.2016
Редакторы: Влад Мержевич, Клим Щербаков