Модуль deferred

Модуль deferred в Zepto реализует механизм управления асинхронными операциями, аналогичный Promises в современном JavaScript. Он позволяет создавать цепочки действий, которые выполняются после завершения асинхронного процесса, обеспечивая более чистую и управляемую архитектуру кода.


Создание Deferred объектов

Deferred объект создаётся с помощью функции $.Deferred():

var deferred = $.Deferred();

Этот объект содержит методы для управления состоянием асинхронной операции:

  • resolve(value) — переводит объект в состояние resolved и передаёт результат value всем подписанным обработчикам.
  • reject(reason) — переводит объект в состояние rejected и передаёт причину reason подписчикам.
  • promise() — возвращает только публичную часть объекта, не позволяя внешнему коду напрямую изменять его состояние.

Пример использования:

var deferred = $.Deferred();

deferred.done(function(result) {
    console.log("Успех:", result);
}).fail(function(error) {
    console.log("Ошибка:", error);
});

// Асинхронная операция
setTimeout(function() {
    deferred.resolve("Данные загружены");
}, 1000);

Методы для подписки на события

Deferred объект поддерживает несколько основных методов для подписки:

  1. done(callback) — вызывается при успешном завершении операции.
  2. fail(callback) — вызывается при ошибке.
  3. always(callback) — вызывается в любом случае, независимо от успеха или ошибки.
  4. progress(callback) — поддержка уведомлений о промежуточном состоянии (редко используется в Zepto, но присутствует для совместимости).

Пример цепочки:

var deferred = $.Deferred();

deferred
    .progress(function(progress) { console.log("Прогресс:", progress); })
    .done(function(result) { console.log("Результат:", result); })
    .fail(function(err) { console.log("Ошибка:", err); })
    .always(function() { console.log("Операция завершена"); });

deferred.notify("50%");
deferred.resolve("Готово");

Метод notify позволяет отправлять промежуточные уведомления через progress.


Метод then

Метод then обеспечивает цепочку асинхронных действий и позволяет обрабатывать результат или ошибку:

deferred.then(
    function(result) { return result + " обработано"; },
    function(error) { return "Ошибка обработана"; }
);

Особенности:

  • Возвращает новый Deferred объект, что позволяет строить цепочки промисов.
  • Первый аргумент — функция для успешного завершения.
  • Второй аргумент — функция для обработки ошибки.

Пример цепочки:

$.Deferred(function(defer) {
    setTimeout(function() { defer.resolve(5); }, 500);
})
.then(function(value) {
    console.log("Первый then:", value);
    return value * 2;
})
.then(function(value) {
    console.log("Второй then:", value);
});

Вывод будет:

Первый then: 5
Второй then: 10

Объединение нескольких Deferred объектов

Zepto поддерживает метод $.when, который позволяет ожидать несколько Deferred объектов одновременно:

var d1 = $.Deferred();
var d2 = $.Deferred();

$.when(d1, d2).done(function(res1, res2) {
    console.log("Результаты:", res1, res2);
});

setTimeout(function() { d1.resolve("Первый"); }, 1000);
setTimeout(function() { d2.resolve("Второй"); }, 1500);

Особенности:

  • Если все Deferred объекты завершены успешно — вызывается done.
  • Если хотя бы один объект завершился с ошибкой — вызывается fail.
  • Позволяет строить сложные асинхронные схемы с параллельными операциями.

Применение в AJAX-запросах

Zepto интегрирует Deferred с AJAX через метод $.ajax, возвращая объект, совместимый с Deferred:

$.ajax({
    url: "/data.json",
    type: "GET"
})
.done(function(data) {
    console.log("Данные получены:", data);
})
.fail(function() {
    console.log("Ошибка загрузки данных");
});

Преимущества:

  • Возможность использования цепочек then.
  • Возможность объединения нескольких AJAX-запросов через $.when.
  • Единая обработка успеха и ошибок для асинхронного кода.

Состояния Deferred

Deferred объект может находиться в одном из трёх состояний:

  • pending — начальное состояние, операция ещё не завершена.
  • resolved — операция выполнена успешно.
  • rejected — операция завершилась с ошибкой.

Метод state() позволяет получить текущее состояние:

var d = $.Deferred();
console.log(d.state()); // "pending"
d.resolve();
console.log(d.state()); // "resolved"

Важные нюансы

  1. Deferred и jQuery-подобные цепочки Методы done, fail, always могут быть вызваны несколько раз. Все добавленные функции будут выполнены при переходе в соответствующее состояние.

  2. Отложенные объекты как промисы Рекомендуется отдавать наружу только promise(), чтобы внешние модули не могли вызвать resolve или reject напрямую.

  3. Совместимость с стандартом Promises Zepto Deferred не полностью совместим с нативными Promise, но базовые функции (then, done, fail) работают аналогично.


Практическая схема использования

  1. Создание Deferred объекта.
  2. Выполнение асинхронной операции (AJAX, таймер, обработка файла).
  3. Вызов resolve или reject при завершении.
  4. Подписка через done, fail, always или then.
  5. При необходимости объединение нескольких Deferred через $.when.

Эта схема позволяет строить чистый и управляемый асинхронный код, избегая “адских колбэков” и упрощая обработку ошибок и цепочек действий.