Улучшить документацию Просмотреть исходный код $q
- $qProvider
- Сервис в модуле ng
Обзор
Сервис, который помогает выполнять асинхронные функции и использовать их возвращаемые значения (или исключения) по завершении обработки.
Это реализация обещаний/отложенных объектов, совместимая с Promises/A+, вдохновлённая Q Криса Коваля.
$q может использоваться двумя способами — один, более похожий на реализацию Q Криса Коваля или Deferred в jQuery, и другой, в некоторой степени напоминающий обещания ES6 (ES2015).
$q конструктор
Упрощённое обещание в стиле ES6 в основном использует $q как конструктор, принимающий resolver функцию в качестве первого аргумента. Это аналогично реализации Promise из ES6, см. MDN.
Хотя использование конструктора поддерживается, не все поддерживающие методы из обещаний ES6 доступны пока.
Он может использоваться так:
// for the purpose of this example let's assume that variables `$q` and `okToGreet`
// are available in the current lexical scope (they could have been injected or passed in).
function asyncGreet(name) {
// perform some asynchronous operation, resolve or reject the promise when appropriate.
return $q(function(resolve, reject) {
setTimeout(function() {
if (okToGreet(name)) {
resolve('Hello, ' + name + '!');
} else {
reject('Greeting ' + name + ' is not allowed.');
}
}, 1000);
});
}
var promise = asyncGreet('Robin Hood');
promise.then(function(greeting) {
alert('Success: ' + greeting);
}, function(reason) {
alert('Failed: ' + reason);
});
Примечание: обратные вызовы progress/notify в настоящее время не поддерживаются через интерфейс в стиле ES6.
Примечание: в отличие от поведения ES6, исключение, брошенное в функции конструктора, НЕ подразумевает немедленного отклонения обещания.
Однако более традиционное использование в стиле CommonJS всё ещё доступно и описано ниже.
Предложение CommonJS для обещаний описывает обещание как интерфейс для взаимодействия с объектом, представляющим результат асинхронного действия, которое может быть завершено или нет в любой момент времени.
С точки зрения обработки ошибок, API отложенных объектов и обещаний являются для асинхронного программирования тем же, чем try, catch и throw ключевые слова для синхронного программирования.
// for the purpose of this example let's assume that variables `$q` and `okToGreet`
// are available in the current lexical scope (they could have been injected or passed in).
function asyncGreet(name) {
var deferred = $q.defer();
setTimeout(function() {
deferred.notify('About to greet ' + name + '.');
if (okToGreet(name)) {
deferred.resolve('Hello, ' + name + '!');
} else {
deferred.reject('Greeting ' + name + ' is not allowed.');
}
}, 1000);
return deferred.promise;
}
var promise = asyncGreet('Robin Hood');
promise.then(function(greeting) {
alert('Success: ' + greeting);
}, function(reason) {
alert('Failed: ' + reason);
}, function(update) {
alert('Got notification: ' + update);
});
На первый взгляд может показаться не очевидным, почему эта дополнительная сложность стоит усилий. Вознаграждение заключается в гарантиях, которые предоставляют API обещаний и отложенных объектов, см. https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
Кроме того, API обещаний позволяет осуществлять композицию, что очень сложно сделать с традиционным подходом обратного вызова (CPS). Более подробную информацию см. в документации Q, особенно в разделе о последовательном или параллельном объединении обещаний.
API отложенных объектов
Новый экземпляр отложенного объекта создаётся путём вызова $q.defer().
Цель объекта отложенного объекта — предоставить связанный экземпляр обещания, а также API, которые могут использоваться для сигнализации об успешном или неуспешном завершении, а также о статусе задачи.
Методы
-
resolve(value)— разрешает производное обещание со значениемvalue. Если значение является объектом отклонения, созданным с помощью$q.reject, обещание будет отклонено вместо этого. -
reject(reason)— отклоняет производное обещание со значениемreason. Это эквивалентно разрешению с объектом отклонения, созданным с помощью$q.reject. -
notify(value)— предоставляет обновления о статусе выполнения обещания. Это может вызываться несколько раз до тех пор, пока обещание не будет разрешено или отклонено.
Свойства
- promise —
{Promise}— объект обещания, связанный с этим отложенным объектом.
API обещаний
Новый экземпляр обещания создаётся при создании экземпляра отложенного объекта и может быть получен путём вызова deferred.promise.
Цель объекта обещания — предоставить заинтересованным сторонам доступ к результату задачи, отложенной на выполнение, по её завершении.
Методы
-
then(successCallback, [errorCallback], [notifyCallback])— независимо от того, когда обещание было или будет разрешено или отклонено,thenасинхронно вызывает один из обратных вызовов успеха или ошибки, как только результат станет доступен. Обратные вызовы вызываются с одним аргументом: результатом или причиной отклонения. Кроме того, обратный вызов notify может вызываться ноль или более раз, чтобы предоставить индикацию прогресса, прежде чем обещание будет разрешено или отклонено.Этот метод возвращает новое обещание, которое разрешается или отклоняется с помощью возвращаемого значения
successCallback,errorCallback(если это значение не является обещанием, в таком случае оно разрешается с помощью значения, разрешённого в этом обещании с помощью цепочки обещаний). Оно также отправляет уведомления через возвращаемое значение методаnotifyCallback. Обещание не может быть разрешено или отклонено из метода notifyCallback. Аргументы errorCallback и notifyCallback необязательны. -
catch(errorCallback)— сокращение дляpromise.then(null, errorCallback) -
finally(callback, notifyCallback)— позволяет наблюдать за выполнением или отклонением обещания, но без изменения конечного значения. Это полезно для освобождения ресурсов или выполнения некоторых действий по очистке, которые должны быть выполнены, независимо от того, было ли обещание отклонено или разрешено. Более подробную информацию см. в полном спецификации.
Цепочки обещаний
Поскольку вызов метода then обещания возвращает новое производное обещание, легко создать цепочку обещаний:
promiseB = promiseA.then(function(result) {
return result + 1;
});
// promiseB will be resolved immediately after promiseA is resolved and its value
// will be the result of promiseA incremented by 1
Можно создавать цепочки любой длины, и поскольку обещание может быть разрешено другим обещанием (которое отложит своё разрешение), можно приостановить/отложить разрешение обещаний в любой точке цепочки. Это позволяет реализовывать мощные API, такие как обработчики ответов $http.
Различия между Q Криса Коваля и $q
Есть два основных отличия:
- $q интегрирован с механизмом наблюдения модели
$rootScope.ScopeScope в AngularJS, что означает более быстрое распространение разрешения или отклонения в ваши модели и предотвращение ненужных перерисовок браузера, что приводило бы к мерцанию пользовательского интерфейса. - Q имеет больше возможностей, чем $q, но это влечёт за собой дополнительные байты. $q компактен, но содержит всю необходимую функциональность для выполнения типичных асинхронных задач.
Тестирование
it('should simulate promise', inject(function($q, $rootScope) {
var deferred = $q.defer();
var promise = deferred.promise;
var resolvedValue;
promise.then(function(value) { resolvedValue = value; });
expect(resolvedValue).toBeUndefined();
// Simulate resolving of promise
deferred.resolve(123);
// Note that the 'then' function does not get called synchronously.
// This is because we want the promise API to always be async, whether or not
// it got called synchronously or asynchronously.
expect(resolvedValue).toBeUndefined();
// Propagate promise resolution to 'then' functions using $apply().
$rootScope.$apply();
expect(resolvedValue).toEqual(123);
}));
Зависимости
Использование
$q(resolver);
Аргументы
| Параметр | Тип | Подробности |
|---|---|---|
| resolver | function(function, function) | Функция, ответственная за разрешение или отклонение вновь созданного промиса. Первый параметр — функция, разрешающая промис, второй — функция, отклоняющая промис. |
Возвращаемое значение
Promise |
Новый созданный промис. |
Методы
-
defer();
Создаёт объект
Deferred, представляющий задачу, которая завершится в будущем.Возвращаемое значение
DeferredВозвращает новый экземпляр объекта deferred.
-
reject(reason);
Создаёт промис, который отклоняется с указанным
reason. Этот API используется для передачи отклонения в цепочке промисов. Если вы работаете с последним промисом в цепочке, об этом беспокоиться не нужно.При сравнении объектов deferred/promised с привычным поведением try/catch/throw,
rejectможно рассматривать как ключевое словоthrowв JavaScript. Это также означает, что если вы «перехватываете» ошибку через обработчик ошибок промиса и хотите передать ошибку промису, полученному из текущего промиса, вы должны «перебросить» ошибку, вернув отклонение, созданное с помощьюreject.promiseB = promiseA.then(function(result) { // success: do something and resolve promiseB // with the old or a new result return result; }, function(reason) { // error: handle the error if possible and // resolve promiseB with newPromiseOrValue, // otherwise forward the rejection to promiseB if (canHandle(reason)) { // handle the error and recover return newPromiseOrValue; } return $q.reject(reason); });Параметры
Параметр Тип Подробности reason *Постоянная, сообщение, исключение или объект, представляющий причину отклонения.
Возвращаемое значение
PromiseВозвращает промис, который уже был отклонен с
reason. -
when(value, [successCallback], [errorCallback], [progressCallback]);
Оборачивает объект, который может быть значением или (сторонним) промисом, в промис $q. Это полезно, когда вы имеете дело с объектом, который может или не может быть промисом, или если промис поступает из ненадежного источника.
Параметры
Параметр Тип Подробности value *Значение или промис
successCallback (необязательно)Function=errorCallback (необязательно)Function=progressCallback (необязательно)Function=Возвращаемое значение
PromiseВозвращает промис переданного значения или промиса
-
resolve(value, [successCallback], [errorCallback], [progressCallback]);
Псевдоним для when для сохранения согласованности именования с ES6.
Параметры
Параметр Тип Подробности value *Значение или промис
successCallback (необязательно)Function=errorCallback (необязательно)Function=progressCallback (необязательно)Function=Возвращаемое значение
PromiseВозвращает промис переданного значения или промиса
-
all(promises);
Объединяет несколько промисов в один промис, который разрешается, когда все входные промисы разрешены.
Параметры
Параметр Тип Подробности promises Array.<Promise>Object.<Promise>Массив или хеш промисов.
Возвращаемое значение
PromiseВозвращает одиночный промис, который будет разрешён массивом/хешем значений, каждое значение соответствует промису на том же индексе/ключе в массиве/хеше
promises. Если любой из промисов отклоняется, этот результирующий промис отклоняется с тем же значением отклонения. -
race(promises);
Возвращает промис, который разрешается или отклоняется, как только один из этих промисов разрешается или отклоняется, со значением или причиной от этого промиса.
Параметры
Параметр Тип Подробности promises Array.<Promise>Object.<Promise>Массив или хеш промисов.
Возвращаемое значение
PromiseПромис, который разрешается или отклоняется, как только один из
promisesразрешается или отклоняется, со значением или причиной от этого промиса.
© 2010–2018 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://code.angularjs.org/1.6.9/docs/api/ng/service/$q