Promise в Ajax-запросах
Как видно из примеров прошлых тем для создания ajax-запросов используются фактически повторяющиеся вызовы, отличающиеся лишь деталями - строкой запроса, функциями обработки ответа. И вполне было бы не плохо создать для всех действий, связанных с асинхронным ajax-запросом, создать какую-то общую абстракцию и затем использовать ее при следующих обращениях к серверу.
Для создания дополнительного уровня абстракции в данном случае удобно применять объект Promise, который обертывает асинхронную операцию в один объект, который позволяет определить действия, выполняющиеся при успешном или неудачном выполнении этой операции.
Инкапсулируем асинхронный запрос в объект Promise:
function get(url) {
return new Promise(function(succeed, fail) {
var request = new XMLHttpRequest();
request.open("GET", url, true);
request.addEventListener("load", function() {
if (request.status < 400)
succeed(request.response);
else
fail(new Error("Request failed: " + request.statusText));
});
request.addEventListener("error", function() {
fail(new Error("Network error"));
});
request.send();
});
}
Метод get получает в качестве параметра адрес ресурса сервера и возвращает объект Promise. Конструктор Promise в качестве параметра принимает функцию обратного вызова, которая в свою очередь принимает два параметра - две функции: одна выполняется при успешной обработке запроса, а вторая - при неудачной.
Допустим, на сервере будет размещен файл users.json со следующим содержимым:
[
{
"name": "Tom",
"age": 34
}, {
"name": "Sam",
"age": 32
}, {
"name": "Bob",
"age": 26
}
]
Теперь вызовем метод get для осуществления запроса к серверу:
get("http://localhost:8080/users.json").then(function(text) {
console.log(text);
}, function(error) {
console.log("Error!!!");
console.log(error);
});
Для обработки результата объекта Promise вызывается метод then(), который принимает два параметра: функцию, вызываемую при успешном выполнении запроса, и функцию, которая вызывается при неудачном выполнении запроса. Метод then() также возвращает объект Promise. Поэтому при необходимости мы можем применить к его результату цепочки вызовов метода then: get().then().then().... Например:
get("http://localhost:8080/users.json").then(function(response) {
console.log(response);
return JSON.parse(response);
}).then(function(data) {
console.log(data[0]);
});
В данном случае функция в первом вызове метода then получает ответ сервера и возвращает распарсенные данные в виде массива с помощью функции JSON.parse().
Функция во втором вызове then получает эти распарсенные данные, то есть массив, в виде параметра (возвращаемое значение предудыщего then является параметром для последующего then). Затем первый элемент массива выводится на консоль.
Для обработки ошибок мы мы можем использовать метод catch(), в который передается функция обработки ошибок:
get("http://localhost:8080/users.jsn").then(function(response) {
console.log(response);
return JSON.parse(response);
}).then(function(data) {
console.log(data[0]);
}).catch(function(error){
console.log("Error!!!");
console.log(error);
});
Подобным образом через Promise можно было бы отправлять данные на сервер:
function post(url, requestuestBody) {
return new Promise(function(succeed, fail) {
var request = new XMLHttpRequest();
request.open("POST", url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.addEventListener("load", function() {
if (request.status < 400)
succeed(request.responseText);
else
fail(new Error("Request failed: " + request.statusText));
});
request.addEventListener("error", function() {
fail(new Error("Network error"));
});
request.send(requestuestBody);
});
}
var user = {
name: "Tom&Tim",
age: 23
};
// данные для отправки
var params = "name=" + user.name + "&age="+user.age;
post("http://localhost:8080/postdata.php", params).then(function(text) {
console.log(text);
}, function(error) {
console.log(error);
});
Output