Куки
Одну из возможностей сохранения данных в JavaScript представляет использование куки. Для работы с куками в объекте document предназначено свойство cookie.
Для установки куков достаточно свойству document.cookie присвоить строку с куками:
document.cookie = "login=tom32;";
В данном случае устанавливается кука, которая называется "login" и которая имеет значение "tom32". И в большинстве браузеров мы можем посмотреть ее, узнать всю информацию о ней и в дальнейшем ее можно использовать в приложении. Строка куки принимает до шести различных параметров: имя куки, значение, срок окончания действия (expires), путь (path), домен (domain) и secure. Выше использовались только два параметра: имя куки и значение. То есть в случае со строкой "login=tom32;" куки имеет имя login и значение tom32.
Но подобная куки имеет очень ограниченный срок жизни: если явным образом не установить срок действия, то кука будет удалена с закрытием браузера. Подобная ситуация, возможно, идеальна для тех случаев, когда необходимо удалять всю информацию после завершения работы с веб-приложением и закрытия браузера. Однако данное поведение не всегда подходит.
- Получение куки
Для простейшего извлечения куки из браузера достаточно обратиться к свойству document.cookie:
var expire = new Date(); expire.setHours(expire.getHours() + 4); document.cookie = "city=Berlin;expires="+expire.toUTCString()+";"; document.cookie = "country=Germany;expires="+expire.toUTCString()+";"; document.cookie = "login=tom32;"; document.write(document.cookie);
Здесь были установлены три куки, и браузер выведет нам все эти куки.
Web storage
Хотя куки позволяют сохранять информацию, они имеют ряд ограничений. Например, браузер имеет ограничения на размер куков - каждая кука не может превышать 4 кб. Куки имеют срок действия, после которого удаляются. Куки являются неотъемлемой чертой протокола HTTP и при каждом запросе к серверу передаются вместе с запросом на сервер. Однако для работы с куками на стороне клиента в коде JavaScript не имеет значения передача куков на сервер. Кроме того, для извлечения сохраненных куков надо написать некоторую порцию кода.
Поэтому в HTML5 была внедрена новая концепция для хранения данных - web storage. Web storage состоит из двух компонентов: session storage и local storage.
Session storage представляет временное хранилище информации, которая удаляется после закрытия браузера.
Local storage представляет хранилище для данных на постоянной основе. Данные из local storage автоматически не удаляются и не имеют срока действия. Эти данные не передаются на сервер в запросе HTTP. Кроме того, объем local storage составляет в Chrome и Firefox 5 Mб для домена, а в IE - 10 Mб.
Все данные в web storage представляют набор пар ключ-значение. То есть каждый объект имеет уникальное имя-ключ и определенное значение.
Для работы с local storage в JavaScript используется объект localStorage, а для работы с session storage - объект sessionStorage.
Для сохранения данных надо передать в метод setItem() объекта localStorage:
localStorage.setItem("login", "tom32@gmail.com");
В этот метод передаются два значения: ключ и значение сохраняемого объекта.
Если в localStorage уже есть объект с ключом "login", то его значение заменяется новым.
Для получения сохраненных данных надо вызвать метод getItem():
var login = localStorage.getItem("login"); console.log(login); // tom32@gmail.com
В этот метод передается ключ объекта.
Чтобы удалить объект, применяется метод removeItem(), который принимает ключ удаляемого объекта:
localStorage.removeItem("login");
И для полного удаления всех объектов из localStorage можно использовать метод clear():
localStorage.clear();
С сохранением простых объектов все просто, однако при этом надо учитывать, что данные в localStorage сохраняются в виде строки:
localStorage.setItem("age", 23); var age = localStorage.getItem("age"); age=parseInt(age)+10; document.write(age); //33
Если в данном случае не преобразовать значение к числу с помощью parseInt(), то age будет действовать как строка.
Трудности могут возникнуть с сохранением сложных объектов:
var user ={ name: "Tom", age: 23, married: false }; localStorage.setItem("user", user); var savedUser = localStorage.getItem("user"); document.write(savedUser); //[object Object] document.write(savedUser.name); // undefined - savedUser - строка, а не объект
В этом случае нам надо использовать сериализацию в формат JSON:
var user ={ name: "Tom", age: 23, married: false }; localStorage.setItem("user", JSON.stringify(user)); var savedUser = JSON.parse(localStorage.getItem("user")); document.write(savedUser.name + " " + savedUser.age +" " + savedUser.married); // Tom 23 false
AJAX
Современные веб-приложения, как правило, разделяются на две части: клиент и сервер. Клиент представляет собой веб-страницу с кодом JavaScript. К серверным технологиям относятся PHP, Ruby, Node.js, ASP.NET и т.д., которые получают запрос от клиента, обрабатывают и отправляют в ответ результат обработки.
AJAX представляет технологию для отправки запросов к серверу из клиентского кода JavaScript без перезагрузки страницы. Сам термин расшифровывается как Asynchronous JavaScript And XML. То есть изначально AJAX предполагал асинхронное взаимодействие клиента и сервера посредством данных в формате XML. Хотя сейчас XML во многом вытеснил формат JSON. В любом случае AJAX революционизировал веб-среду, позволив создавать динамичные отзывчивые веб-приложения.
- Объект XMLHttpRequest
Для создания приложений, использующих AJAX, применяются различные способы. Но самым распространенным способом является использование объекта XMLHttpRequest:
var request = new XMLHttpRequest();
После создания объекта XMLHttpRequest можно отправлять запросы к серверу. Но для начала надо вызвать метод open() для инициализации:
request.open("GET", "http://localhost/hello.txt", false);
Метод open() принимает три параметра: тип запроса (GET, POST, HEAD, PUT), адрес запроса и третий необязательный параметр - логическое значение true или false, указывающее, будет ли запрос осуществляться в асинхронном режиме. То есть в данном случае запрос будет иметь тип GET, он будет направляться по адресу "http://localhost/hello.txt в синхронном режиме, так как стоит значение false (для асинхронного режима указывается значение true).
Синхронный и асинхронный режим отличаются тем, что запрос в синхронном режиме пока запрос не выполнится, остальной код JavaScript не может выполняться. По умолчанию, если третий параметр не используется, то запрос отправляется в асинхронном режиме, что позволяет параллельно с выполнением запроса выполнять также и другой код JavaScript. И в большинстве случаев, как правило, используется именно асинхронный режим.
Кроме того, метод open() может принимать еще два параметра: логин и пароль пользователя, если для выполнения запроса нужна аутентификация:
request.open("GET", "http://localhost/home.php", true, "login", "password");
После инициализации запроса методом open() необходимо отправить запрос с помощью метода send():
request.send();
- Свойства XMLHttpRequest
Объект XMLHttpRequest имеет ряд свойств, которые позволяют проконтролировать выполнение запроса:
Например, выполним запрос к текстовому файлу, который находится на локальном веб-сервере. Для выполнения ajax-запросов потребуется запущенный локальный веб-сервер, на котором будет лежать файл hello.txt, в котором будет содержаться одна строка: "Привет мир".
Код веб-страницы (пусть она называется test.html) будет следующим:
var request = new XMLHttpRequest(); request.open("GET", "/hello.txt", false); request.send(); var status = request.status; if(status == 200) { document.write("Текст ответа: " + request.responseText) } else if(status == 404) { document.write("Ресурс не найден") } else { document.write(request.statusText) }
И после загрузки страницы выполнится ajax-запрос к ресурсу /hello.txt. Но важно отметить, что получение статуса сразу после вызова метода request.send() будет работать только для синхронного запроса.
- Асинхронные запросы
Хотя синхронные запросы вполне работают и их можно использовать, но в то же время их рекомендуется избегать. Поскольку нередко запрос может занять продолжительное время, то это может заблокировать выполнение остального кода и работу с html-страницей до окончания выполнения запроса. Поэтому рекомендуется использовать преимущественно асинхронные запросы.
Работа с асинхронными запросами чуть более сложна, чем с синхронными, поскольку нам надо еще обработать событие readystatechange объекта XMLHttpRequest.
При асинхронном запросе объект XMLHttpRequest использует свойство readyState для хранения состояния запроса. Состояние запроса представляет собой число:
Событие readystatechange возникает каждый раз, когда изменяется значение свойства readyState. Например, выполним асинхронный запрос:
var request = new XMLHttpRequest(); function reqReadyStateChange() { if (request.readyState == 4) { var status = request.status; if (status == 200) { document.write(request.responseText); } else { document.write("Ответ сервера " + request.statusText); } } } request.open("GET", "/hello.txt"); request.onreadystatechange = reqReadyStateChange; request.send();
Кроме обработки события readystatechange для получения ответа сервера можно также обрабатывать событие load, которое возникает после выполнения запроса. Его использование аналогично:
var request = new XMLHttpRequest(); function responceLoad() { if (request.readyState == 4) { var status = request.status; if (status == 200) { document.write(request.responseText); } else { document.write("Ответ сервера " + request.statusText); } } } request.open("GET", "/hello.txt"); request.onload = responceLoad; request.send();
Отправка данных
Принцип отправки данных может отличаться в различных ситуациях. Рассмотрим эти ситуации.
- Отправка GET-запроса
GET-запрос характеризуется тем, что данные могут отправляться в строке запроса:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head> <body> <div id="output"></div> <script> // объект для отправки var user = { name: "Tom", age: 23 }; var request = new XMLHttpRequest(); function reqReadyStateChange() { if (request.readyState == 4) { var status = request.status; if (status == 200) { document.getElementById("output").innerHTML = request.responseText; } } } // строка с параметрами для отправки var body = "name=" + user.name + "&age="+user.age; request.open("GET", "http://localhost:8080/postdata.php?"+body); request.onreadystatechange = reqReadyStateChange; request.send(); </script> </body> </html>
Для отправки берем свойства объекта user и формируем из их значений сроку с параметрами: "name=" + user.name + "&age="+user.age. Затем эта строка добавляется к строке запроса в методе open("GET", "http://localhost:8080/postdata.php?"+body)
- Кодирование параметров
Все отправляемые в GET-запросе параметры разделяются знаком амперсанда(&). Но что, если какой-нибудь параметр имеет знак амперсанда. Например,
var user = { name: "Tom&Tim", age: 23 }; // строка с параметрами для отправки var body = "name=" + user.name + "&age="+user.age;
В этом случае при получении параметров скрипт на стороне сервера может неправильно обработать данные и неправильно извлечь параметры. Поэтому, чтобы кодировать все передаваемые данные, нужно применять функцию encodeURIComponent():
var body = "name=" + encodeURIComponent(user.name) + "&age="+encodeURIComponent(user.age);
При этом строка "Tom&Tim" будет кодирована в следующую строку: "Tom%26Tim".
При необходимости мы можем выполнить обратное декодирование с помощью функции decodeURIComponent():
var encodeName = encodeURIComponent(user.name); // Tom%26Tim var decodeName = decodeURIComponent(encodeName); // Tom&Tim
- POST-запросы
Отправка данных в POST-запросах будет немного отличаться:
var user = { name: "Tom", age: 23 }; var request = new XMLHttpRequest(); function reqReadyStateChange() { if (request.readyState == 4 && request.status == 200) document.getElementById("output").innerHTML=request.responseText; } var body = "name=" + user.name + "&age="+user.age; request.open("POST", "http://localhost:8080/postdata.php"); request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); request.onreadystatechange = reqReadyStateChange; request.send(body);
Для отправки данных методом POST надо установить заголовок Content-Type с помощью метода setRequestHeader(). В данном случае заголовок имеет значение application/x-www-form-urlencoded.
- Отправка данных в формате JSON
Для отправки данных в формате JSON нам необходимо установить соответствующий заголовок и сериализовать данные с помощью метода JSON.stringify:
// объект для отправки var user = { username: "Tom", age: 23 }; var json = JSON.stringify(user); var request = new XMLHttpRequest(); request.open("POST", "http://localhost:8080/postjson.php"); request.setRequestHeader('Content-type', 'application/json; charset=utf-8'); request.onreadystatechange = function () { if (request.readyState == 4 && request.status == 200) document.getElementById("output").innerHTML=request.responseText; } request.send(json);