Создание Deferred

Deferred в jQuery представляет собой объект, предназначенный для управления асинхронными операциями. Он позволяет регистрировать функции обратного вызова (callbacks), которые будут вызваны после завершения операции, обработки ошибок или прогресса выполнения. Deferred обеспечивает более удобное и структурированное управление асинхронным кодом по сравнению с классическими колбэками.

Deferred тесно связан с понятием Promise, хотя имеет собственные расширения и возможности, характерные для jQuery. Основные состояния Deferred:

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

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

Для создания Deferred используется метод $.Deferred().

var deferred = $.Deferred();

После этого объект deferred предоставляет методы для управления состояниями и регистрации обработчиков:

  • resolve(value) — переводит объект в состояние resolved и вызывает все зарегистрированные функции успеха (done).
  • reject(reason) — переводит объект в состояние rejected и вызывает все функции отказа (fail).
  • notify(progress) — отправляет промежуточное уведомление, вызывая функции прогресса (progress).

Регистрация обратных вызовов

Deferred позволяет регистрировать функции обратного вызова через методы:

  • done(callback) — вызывается при успешном завершении.
  • fail(callback) — вызывается при ошибке.
  • progress(callback) — вызывается при уведомлениях о прогрессе.

Пример:

var deferred = $.Deferred();

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

// Симуляция асинхронной операции
setTimeout(function() {
    deferred.notify("50% готово");
    deferred.resolve("Готово");
}, 1000);

В данном примере сначала регистрируются обработчики, затем имитируется асинхронная операция, которая сначала сообщает о прогрессе, а потом завершает Deferred успешно.

Метод promise()

Deferred объект можно использовать совместно с промисами. Метод promise() возвращает объект, который предоставляет только интерфейс для регистрации обратных вызовов (done, fail, progress), исключая методы управления состояниями (resolve, reject). Это позволяет передавать объект другим частям кода, не опасаясь, что его состояние будет изменено извне.

var deferred = $.Deferred();
var promise = deferred.promise();

promise.done(function(result) {
    console.log(result);
});

// Здесь невозможно вызвать deferred.resolve() через promise

Связывание нескольких Deferred

Методы $.when() и then() позволяют комбинировать несколько Deferred объектов.

var task1 = $.Deferred();
var task2 = $.Deferred();

$.when(task1, task2).done(function(result1, result2) {
    console.log("Все задачи завершены:", result1, result2);
});

// Симуляция завершения задач
setTimeout(() => task1.resolve("Результат 1"), 1000);
setTimeout(() => task2.resolve("Результат 2"), 1500);

Метод then() позволяет цепочечно обрабатывать результаты Deferred:

var deferred = $.Deferred();

deferred
    .then(function(result) {
        console.log("Шаг 1:", result);
        return "Результат шаг 2";
    })
    .then(function(result) {
        console.log("Шаг 2:", result);
    });

deferred.resolve("Начальный результат");

Каждый then() возвращает новый Deferred, что позволяет строить последовательные асинхронные цепочки.

Обработка ошибок и завершение

Методы always(callback) и pipe() обеспечивают дополнительную гибкость:

  • always(callback) — вызывается независимо от состояния (успех или ошибка).
  • pipe() (устаревший, заменён на then) — позволяет трансформировать результат Deferred и создавать новые цепочки.
var deferred = $.Deferred();

deferred.always(function(value) {
    console.log("Завершено, независимо от результата:", value);
});

deferred.reject("Ошибка выполнения");

Применение Deferred в реальных задачах

Deferred широко используется для управления асинхронными операциями:

  • AJAX-запросы ($.ajax возвращает Deferred).
  • Загрузка ресурсов (скриптов, изображений).
  • Последовательная обработка нескольких действий, зависимых друг от друга.

Пример с AJAX:

$.ajax("/api/data")
    .done(function(data) {
        console.log("Данные получены:", data);
    })
    .fail(function() {
        console.log("Ошибка запроса");
    });

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

Deferred является фундаментальным инструментом в jQuery для построения надежной асинхронной логики, обеспечивая гибкость и масштабируемость при работе с множеством асинхронных операций.