Улучшить эту документацию Просмотреть исходный код $q
- сервис в модуле ng
Сервис, который помогает запускать функции асинхронно и использовать их возвращаемые значения (или исключения) после завершения обработки.
Это реализация объектов обещаний/отложенных объектов, вдохновлённая 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().
Цель объекта отложенной задачи — предоставить связанный экземпляр Promise, а также 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. -
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 в Angular, что означает более быстрое распространение разрешения или отклонения в модели и предотвращение ненужных перерисовок браузера, которые привели бы к мерцанию пользовательского интерфейса. -
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/promis с привычным поведением 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]);
Оборачивает объект, который может быть значением или (третьей стороной) then-able промисой, в промису $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массиве/хэше. Если какая-либо из промис решена с отклонением, эта результирующая промиса будет отклонена с тем же значением отклонения.
© 2010–2017 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://code.angularjs.org/1.4.14/docs/api/ng/service/$q