Первое, что вы обнаружите при поиске промисов angular и $q, — это отложенный (анти)паттерн, который мы все использовали и до сих пор используем в наших приложениях. Это происходит из-за нашего неправильного понимания асинхронного кода, а затем мы пытаемся писать код асинхронно с синхронными шаблонами, поэтому мы создаем объект отложенного выполнения, который вообще не нужен. Я также виню в этом Angular, так как это находится на их странице документации $q, где отложенный API объясняется без уведомления о лучших практиках.
Вот пример из нашего собственного кода:
В этом примере мы создаем объект отсрочки, а затем вызываем метод отклонения, если получаем ошибку.
Чтобы избавиться от этого анти-шаблона, мы могли бы написать такой код:
Таким образом мы решили даже два антипаттерна. Во-первых, нужно избавиться от объекта отсрочки, так как service.getStatus уже является промисом, и мы можем распространять результаты вверх по цепочке с помощью инструкции return. Второй — заменить функции успеха и ошибки на catch, которые предлагает q или Bluebird. Таким образом, мы получаем более удобочитаемую функцию, и никто не задается вопросом, какая функция что означает (then =› catch =› finally намного понятнее).
Кроме того, отлов ошибок в сервисе не рекомендуется, поэтому код можно было бы упростить:
Таким образом, отлов ошибок будет выполняться в контроллере, и мы сохраним сервис чистым и независимым от форматирования выходных данных конечного пользователя (в этом случае событие, возвращающее ответные данные, не обязательно, но мы можем сделать вид, что сервис выполняет некоторые манипуляции с данными). Чистый сервис можно повторно использовать. С другой стороны, мы не потеряем никаких ошибок или отказов.
Вот более сложный пример этого шаблона:
Вы заметите, что есть несколько промисов, и их результаты распространяются по всей цепочке до вызывающей стороны.
ПРИМЕЧАНИЕ. Пример выше — это метод класса, написанный на es6.
Итак, когда использовать отложенный объект?
Ну, практически никогда, когда дело доходит до работы с объектами, которые можно использовать, но defer можно использовать для преобразования некоторого обратного вызова в функцию, которую можно использовать.
Вот пример, в котором мы создаем объект defer для обещания загрузки изображения:
То же самое можно сделать с помощью конструктора $q:
Спасибо Петке Антонову и его замечательной Библиотеке обещаний Bluebird.