Ждите всех обещаний решить
Поэтому у меня есть ситуация, когда у меня есть несколько цепочек обещаний неизвестной длины. Я хочу, чтобы некоторые действия выполнялись, когда все ЦЕЛИ были обработаны. Возможно ли это? Вот пример:
app.controller('MainCtrl', function($scope, $q, $timeout) { var one = $q.defer(); var two = $q.defer(); var three = $q.defer(); var all = $q.all([one.promise, two.promise, three.promise]); all.then(allSuccess); function success(data) { console.log(data); return data + "Chained"; } function allSuccess(){ console.log("ALL PROMISES RESOLVED") } one.promise.then(success).then(success); two.promise.then(success); three.promise.then(success).then(success).then(success); $timeout(function () { one.resolve("one done"); }, Math.random() * 1000); $timeout(function () { two.resolve("two done"); }, Math.random() * 1000); $timeout(function () { three.resolve("three done"); }, Math.random() * 1000); });
В этом примере я установил $q.all()
для обещаний один, два и три, которые будут решены в какое-то случайное время. Затем я добавляю обещания на концах одного и трех. Я хочу, чтобы все решалось, когда все цепи были разрешены. Вот результат, когда я запускаю этот код:
one done one doneChained two done three done ALL PROMISES RESOLVED three doneChained three doneChainedChained
Есть ли способ дождаться, когда цепи будут решены?
- Как включить Webstorm intellisense для AngularJS при написании CoffeeScript
- Объединение данных между путями на основе идентификатора с помощью AngularFire
- Мне нужно два экземпляра услуги AngularJS $ http или что?
- AngularJS для цикла с числами и диапазонами
- Удаление идентификатора fragmentа из URL-адресов AngularJS (символ #)
- AngularJS - создать директиву, которая использует ng-model
- Как включить один частичный в другой, не создавая новую область?
- AngularJS. Когда выбрано атрибут ng-model, ng-selected не работает
- Как получить данные POST с urlencoded с помощью $ http без jQuery?
- angularjs: настраиваемая директива для проверки наличия имени пользователя
- ng-repeat не обновляется при обновлении массива
- Как установить фокус на поле ввода?
- Угловая динамическая проверка ng-шаблонов
Я хочу, чтобы все решалось, когда все цепи были разрешены.
Конечно, тогда просто передайте promise каждой цепочки во all()
вместо первоначальных обещаний:
$q.all([one.promise, two.promise, three.promise]).then(function() { console.log("ALL INITIAL PROMISES RESOLVED"); }); var onechain = one.promise.then(success).then(success), twochain = two.promise.then(success), threechain = three.promise.then(success).then(success).then(success); $q.all([onechain, twochain, threechain]).then(function() { console.log("ALL PROMISES RESOLVED"); });
Принятый ответ правильный. Я хотел бы привести пример, чтобы немного разобраться с теми, кто не знаком с promise
.
Пример:
В моем примере мне нужно заменить атрибуты src
тегов img
разными зеркальными URL-адресами, если они доступны до рендеринга содержимого.
var img_tags = content.querySelectorAll('img'); function checkMirrorAvailability(url) { // blah blah return promise; } function changeSrc(success, y, response) { if (success === true) { img_tags[y].setAttribute('src', response.mirror_url); } else { console.log('No mirrors for: ' + img_tags[y].getAttribute('src')); } } var promise_array = []; for (var y = 0; y < img_tags.length; y++) { var img_src = img_tags[y].getAttribute('src'); promise_array.push( checkMirrorAvailability(img_src) .then( // a callback function only accept ONE argument. // Here, we use `.bind` to pass additional arguments to the // callback function (changeSrc). // successCallback changeSrc.bind(null, true, y), // errorCallback changeSrc.bind(null, false, y) ) ); } $q.all(promise_array) .then( function() { console.log('all promises have returned with either success or failure!'); render(content); } // We don't need an errorCallback function here, because above we handled // all errors. );
Объяснение:
Из документов AngularJS:
then
метод:
затем (successCallback, errorCallback, notifyCallback) - независимо от того, когда promise было или будет разрешено или отклонено, затем вызывает один из успешных или обратных вызовов асинхронно, как только результат будет доступен. Обратные вызовы вызываются с помощью одного аргумента : причина или отклонение.
$ Q.all (обещания)
Объединяет несколько обещаний в единое promise, которое разрешается, когда все вступительные обещания разрешаются.
Параметр promises
может быть множеством обещаний.
О bind()
, Дополнительная информация здесь: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Недавно возникла эта проблема, но с неподтвержденным количеством обещаний. Решено использовать jQuery.map () .
function methodThatChainsPromises(args) { //var args = [ // 'myArg1', // 'myArg2', // 'myArg3', //]; var deferred = $q.defer(); var chain = args.map(methodThatTakeArgAndReturnsPromise); $q.all(chain) .then(function () { $log.debug('All promises have been resolved.'); deferred.resolve(); }) .catch(function () { $log.debug('One or more promises failed.'); deferred.reject(); }); return deferred.promise; }
Есть выход. $q.all(...
Вы можете проверить следующие вещи:
Вы можете использовать «ожидание» в «асинхронной функции» .
app.controller('MainCtrl', async function($scope, $q, $timeout) { ... var all = await $q.all([one.promise, two.promise, three.promise]); ... }
ПРИМЕЧАНИЕ. Я не уверен на 100%, что вы можете вызвать функцию async из функции non-async и получить правильные результаты.
Тем не менее, это никогда не будет использоваться на веб-сайте. Но для тестирования нагрузки / интеграции … может быть.
Пример кода:
async function waitForIt(printMe) { console.log(printMe); console.log("..."+await req()); console.log("Legendary!") } function req() { var promise = new Promise(resolve => { setTimeout(() => { resolve("DARY!"); }, 2000); }); return promise; } waitForIt("Legen-Wait For It");