Введение
В современном JavaScript приложении встречается много задач, которые выполняются асинхронно (обращение к серверу, анимация, работа с файловой системой, геолокация). В данной статье будут рассмотрены Promise объекты, как один из вариантов организации асинхронного кода.
Асинхронное программирование в JavaScript
Асинхронное программирование в JavaScript не связано с многопоточностью. JavaScript – однопоточный, это означает, что не существует стандартных языковых конструкций, которые позволят создать в приложении дополнительный поток для выполнения параллельных вычислений (единственная возможность организовать настоящую многопоточность – использовать Web Workers). Асинхронное программирование – стиль программирования, при котором результат работы функций доступен не сразу, а через некоторое время. Асинхронная функция – это функция, после вызова которой JavaScript приложение продолжает работать, потому что функция сразу выполняет возврат. Результат работы асинхронной функции становится известным позже, и для того, чтобы оповестить наше приложении о полученных значениях, асинхронная функция вызывает другую функцию (callback), которую мы передаем в аргументах при запуске.
Например, getDataFromServer(onSuccess); getDataFromServer – асинхронная функция, выполняющая запрос на сервер, onSuccess – callback функция или функция обратного вызова, которая запускается при успешном завершении операции обращения к серверу.
Использование callback функций может привести к появлению проблемы, которую называют Pyramid of Doom – callback функция, в которой вызывается асинхронная функция, которой передается callback функция, и в ней же вызывается асинхронная функция и т.д.
step1(function(result1) {
step2(function(result2) {
step3(function(result3) {
// и т.д.
});
});
});
Такой код тяжело читать и сопровождать. Для того, чтобы подобных проблем не было , мы можем использовать различные шаблоны для организации кода. Один из таких шаблонов - Promise. (Другие варианты организации асинхронного кода можно посмотреть в этой статье)
Что такое Promise (ECMAScript 6)
Promise – прокси объект, который представляет еще не известное значение (значение будет доступно после завершения асинхронной операции). С Promise можно ассоциировать две функции: первая - для выполнения операции, если асинхронная задача завершилась успешно. И вторая - для операции в случае ошибки.
Promise может находиться в одном из трех состояний:
- pending;
- fulfilled;
- rejected.
Например, мы выполняем AJAX запрос с помощью асинхронной функции, которая возвращает Promise. Как только мы выполним запрос, функция создаст Promise, который будет в состоянии pending. Когда сервер вернет ответ, Promise перейдет в состояние fulfilled, если ответ был 200 OK, или в состояние rejected, если статус код был 500 Internal Server Error (или другой код ошибки). При переходе в fullfiled состояние Promise будет содержать ответ от сервера, при переходе в rejected – ошибку или текст ошибки (все зависит от реализации асинхронной функции).
Как только Promise меняет свое состояние, запускается функция, которая была зарегистрирована как реакция на соответствующее состояние.
Пример использования асинхронной функции download, которая возвращает Promise:
download("data.txt").then(function (data) {
console.log(data);
}, function (error) {
console.error(error);
});
или такая запись
var p = download("data.txt");
p.then(onFulfilled, onRejected);
function onFulfilled(data) {
console.log(data);
}
function onRejected(error) {
console.error(error);
}
Видео курсы по схожей тематике:
Для того, чтобы установить, что произойдет после завершения асинхронной операции, на объекте Promise необходимо вызвать метод then. Этот метод принимает два аргумента:
- обработчик для состояния fulfilled
- обработчик для состояния rejected
Функцию then можно вызвать в любой момент, даже если асинхронная операция уже завершена и Promise перешел из состояния pending. Если вызвать then на Promise, который уже находится в конкретном состоянии, то будет вызвана соответствующая состоянию функция, переданная в метод then.
Ниже приведен код асинхронной функции download.
function download(url) {
// Создание нового объекта Promise
return new Promise(function (resolve, reject) {
var req = new XMLHttpRequest();
req.open('GET', url);
req.onload = function () {
if (req.status == 200) {
// перевод Promise в состояние fulfilled.
// req.response - данные доступные в функции-обработчике
// перехода состояния
resolve(req.response);
}
else {
// перевод Promise в состояние rejected
reject(Error(req.statusText));
}
};
// Обработка сетевых ошибок
req.onerror = function () {
// перевод Promise в состояние rejected
reject(Error("Network Error"));
};
// отправка запроса на сервер
req.send();
});
}
Бесплатные вебинары по схожей тематике:
Поддержка Promise браузерами http://caniuse.com/#search=Promise
Библиотеки для работы с Promise
Есть много различных библиотек, которые реализуют спецификацию объекта Promise. Поэтому проблему слабой поддержки Promise ECMAScript 6 можно решить, применив одну из следующих библиотек:
jQuery http://jquery.com/
Q https://github.com/kriskowal/q
When https://github.com/cujojs/when
WinJs http://msdn.microsoft.com/en-us/library/windows/apps/br211867.aspx
Статьи по схожей тематике