Kniga-Online.club
» » » » Марейн Хавербеке - Выразительный JavaScript

Марейн Хавербеке - Выразительный JavaScript

Читать бесплатно Марейн Хавербеке - Выразительный JavaScript. Жанр: Программирование издательство неизвестно, год 2004. Так же читаем полные версии (весь текст) онлайн без регистрации и SMS на сайте kniga-online.club или прочесть краткое содержание, предисловие (аннотацию), описание и ознакомиться с отзывами (комментариями) о произведении.
Перейти на страницу:

Основная проблема с приведённой обёрткой – обработка ошибок. Когда запрос возвращает код статуса, обозначающий ошибку (от 400 и выше), он ничего не делает. В некоторых случаях это нормально, но представьте, что мы поставили индикатор загрузки на странице, показывающий, что мы получаем информацию. Если запрос не удался, потому что сервер упал или соединение прервано, страница будет делать вид, что она чем-то занята. Пользователь подождёт немного, потом ему надоест и он решит, что сайт какой-то дурацкий.

Нам нужен вариант, в котором мы получаем предупреждение о неудачном запросе, чтобы мы могли принять меры. Например, мы можем убрать сообщение о загрузке и сообщить пользователю, что что-то пошло не так.

Обработка ошибок в асинхронном коде ещё сложнее, чем в синхронном. Поскольку нам часто приходится отделять часть работы и размещать её в функции обратного вызова, область видимости блока try теряет смысл. В следующем коде исключение не будет поймано, потому что вызов backgroundReadFile возвращается сразу же. Затем управление уходит из блока try, и функция из него не будет вызвана.

try {

  backgroundReadFile("example/data.txt", function(text) {

    if (text != "expected")

      throw new Error("That was unexpected");

  });

} catch (e) {

  console.log("Hello from the catch block");

}

Чтобы обрабатывать неудачные запросы, придётся передавать дополнительную функцию в нашу обёртку, и вызывать её в случае проблем. Другой вариант – использовать соглашение, что если запрос не удался, то в функцию обратного вызова передаётся дополнительный аргумент с описанием проблемы. Пример:

function getURL(url, callback) {

  var req = new XMLHttpRequest();

  req.open("GET", url, true);

  req.addEventListener("load", function() {

    if (req.status < 400)

      callback(req.responseText);

    else

      callback(null, new Error("Request failed: "

                               req.statusText));

  });

  req.addEventListener("error", function() {

    callback(null, new Error("Network error"));

  });

  req.send(null);

}

Мы добавили обработчик события error, который сработает при проблеме с вызовом. Также мы вызываем функцию обратного вызова с аргументом error, когда запрос завершается со статусом, говорящим об ошибке.

Код, использующий getURL, должен проверять не возвращена ли ошибка, и обрабатывать её, если она есть.

getURL("data/nonsense.txt", function(content, error) {

  if (error != null)

    console.log("Failed to fetch nonsense.txt: " + error);

  else

    console.log("nonsense.txt: " + content);

});

С исключениями это не помогает. Когда мы совершаем последовательно несколько асинхронных действий, исключение в любой точке цепочки в любом случае (если только вы не обернули каждый обработчик в свой блок try/catch) вывалится на верхнем уровне и прервёт всю цепочку.

Обещания

Тяжело писать асинхронный код для сложных проектов в виде простых обратных вызовов. Очень легко забыть проверку на ошибку или позволить неожиданному исключению резко прервать программу. Кроме того, организация правильной обработки ошибок и проход ошибки через несколько последовательных обратных вызовов очень утомительна.

Предпринималось множество попыток решить эту проблему дополнительными абстракциями. Одна из наиболее удачных попыток называется обещаниями (promises). Обещания оборачивают асинхронное действие в объект, который может передаваться и которому нужно сделать какие-то вещи, когда действие завершается или не удаётся. Такой интерфейс уже стал частью текущей версии JavaScript, а для старых версий его можно использовать в виде библиотеки.

Интерфейс обещаний не особенно интуитивно понятный, но мощный. В этой главе мы лишь частично опишем его. Больше информации можно найти на www.promisejs.org.

Для создания объекта promises мы вызываем конструктор Promise, задавая ему функцию инициализации асинхронного действия. Конструктор вызывает эту функцию и передаёт ей два аргумента, которые сами также являются функциями. Первая должна вызываться в удачном случае, другая – в неудачном.

И вот наша обёртка для запросов GET, которая на этот раз возвращает обещание. Теперь мы просто назовём его get.

function get(url) {

  return new Promise(function(succeed, fail) {

    var req = new XMLHttpRequest();

    req.open("GET", url, true);

    req.addEventListener("load", function() {

      if (req.status < 400)

        succeed(req.responseText);

      else

        fail(new Error("Request failed: " + req.statusText));

    });

    req.addEventListener("error", function() {

      fail(new Error("Network error"));

    });

    req.send(null);

  });

}

Заметьте, что интерфейс к самой функции упростился. Мы передаём ей URL, а она возвращает обещание. Оно работает как обработчик для выходных данных запроса. У него есть метод then, который вызывается с двумя функциями: одной для обработки успеха, другой – для неудачи.

get("example/data.txt").then(function(text) {

  console.log("data.txt: " + text);

}, function(error) {

  console.log("Failed to fetch data.txt: " + error);

});

Пока это всё ещё один из способов выразить то же, что мы уже сделали. Только когда у вас появляется цепь событий, становится видна заметная разница.

Вызов then производит новое обещание, чей результат (значение, передающееся в обработчики успешных результатов) зависит от значения, возвращаемого первой переданной нами в then функцией. Эта функция может вернуть ещё одно обещание, обозначая что проводится дополнительная асинхронная работа. В этом случае обещание, возвращаемое then само по себе будет ждать обещания, возвращённого функцией-обработчиком, и успех или неудача произойдут с таким же значением. Когда функция-обработчик возвращает значение, не являющееся обещанием, обещание, возвращаемое then, становится успешным, в качестве результата используя это значение.

Значит, вы можете использовать then для изменения результата обещания. К примеру, следующая функция возвращает обещание, чей результат – содержимое с данного URL, разобранное как JSON:

function getJSON(url) {

  return get(url).then(JSON.parse);

}

Последний вызов then не обозначил обработчик неудач. Это допустимо. Ошибка будет передана в обещание, возвращаемое через then, а ведь это нам и надо – getJSON не знает, что делать, когда что-то идёт не так, но есть надежда, что вызывающий её код это знает.

В качестве примера, показывающего использование обещаний, мы напишем программу, получающую число JSON-файлов с сервера, и показывающую во время исполнения запроса слово «загрузка». Файлы содержат информацию о людях и ссылки на другие файлы с информацией о других людях в свойствах типа отец, мать, супруг.

Нам нужно получить имя матери супруга из example/bert.json. В случае проблем нам нужно убрать текст «загрузка» и показать сообщение об ошибке. Вот как это можно делать при помощи обещаний:

<script>

  function showMessage(msg) {

    var elt = document.createElement("div");

    elt.textContent = msg;

    return document.body.appendChild(elt);

  }

  var loading = showMessage("Загрузка...");

  getJSON("example/bert.json").then(function(bert) {

    return getJSON(bert.spouse);

  }).then(function(spouse) {

    return getJSON(spouse.mother);

  }).then(function(mother) {

    showMessage("Имя - " + mother.name);

  }).catch(function(error) {

    showMessage(String(error));

  }).then(function() {

    document.body.removeChild(loading);

  });

</script>

Итоговая программа относительно компактна и читаема. Метод catch схож с then, но он ожидает только обработчик неудачного результата и в случае успеха передаёт дальше неизменённый результат. Исполнение программы будет продолжено обычным путём после отлова исключения – так же, как в случае с try/catch. Таким образом, последний then, удаляющий сообщение о загрузке, выполняется в любом случае, даже в случае неудачи.

Можно представлять себе, что интерфейс обещаний – это отдельный язык для асинхронной обработки исполнения программы. Дополнительные вызовы методов и функций, которые нужны для его работы, придают коду несколько странный вид, но не настолько неудобный, как обработка всех ошибок вручную.

Цените HTTP

При создании системы, в которой программа на JavaScript в браузере (клиентская) общается с серверной программой, можно использовать несколько вариантов моделирования такого общения.

Общепринятый метод – удалённые вызовы процедур. В этой модели общение идёт по шаблону обычных вызовов функций, только функции эти выполняются на другом компьютере. Вызов заключается в создании запроса на сервер, в который входят имя функции и аргументы. Ответ на запрос включает возвращаемое значение.

Перейти на страницу:

Марейн Хавербеке читать все книги автора по порядку

Марейн Хавербеке - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки kniga-online.club.


Выразительный JavaScript отзывы

Отзывы читателей о книге Выразительный JavaScript, автор: Марейн Хавербеке. Читайте комментарии и мнения людей о произведении.


Уважаемые читатели и просто посетители нашей библиотеки! Просим Вас придерживаться определенных правил при комментировании литературных произведений.

  • 1. Просьба отказаться от дискриминационных высказываний. Мы защищаем право наших читателей свободно выражать свою точку зрения. Вместе с тем мы не терпим агрессии. На сайте запрещено оставлять комментарий, который содержит унизительные высказывания или призывы к насилию по отношению к отдельным лицам или группам людей на основании их расы, этнического происхождения, вероисповедания, недееспособности, пола, возраста, статуса ветерана, касты или сексуальной ориентации.
  • 2. Просьба отказаться от оскорблений, угроз и запугиваний.
  • 3. Просьба отказаться от нецензурной лексики.
  • 4. Просьба вести себя максимально корректно как по отношению к авторам, так и по отношению к другим читателям и их комментариям.

Надеемся на Ваше понимание и благоразумие. С уважением, администратор kniga-online.


Прокомментировать
Подтвердите что вы не робот:*
Подтвердите что вы не робот:*