WedX - журнал о программировании и компьютерных науках

Как создавать обещания из асинхронных API с древовидной структурой в AngularJS

Как дождаться разрешения неопределенных рекурсивных обещаний

У меня проблемы с управлением потоком в моем приложении. У меня есть иерархическая (семейная?) структура данных, например:

{name: "Bob", children: [{name: "Tim", children: [..]}, {another child..}]}

Эта структура может иметь многоуровневую структуру.

Теперь то, что я пытаюсь сделать, это рекурсивно перебрать всех людей, получить их идентификатор, сделать вызов API, чтобы получить изображение для этого человека.

Псевдокод:

gatherPicture(hierarchy);
console.log("I want to wait before doing this!") // Logs too early
function gatherPicture(person) {
    // api request (promise)
    getPicture(person.id).then(r => {
        person.picture = r;
        person.children.forEach(gatherPicture);
    }) 
}

Надеюсь, этот код имеет смысл. Как мне заставить мой код ждать, пока функция collectPicture не обработает и не разрешит всех людей?

Если это что-то добавит, я использую AngularJS и имею доступ к доступной службе $q promise. Но я просто не понимаю, как настроить эту конкретную цепочку промисов, потому что они встроены в рекурсивную функцию.

Спасибо большое!


  • Структура называется деревом 21.08.2018
  • Релевантно: stackoverflow.com/a/50519124/633183 21.08.2018
  • В ответах здесь используются общие обещания ES6. Имейте в виду, что промисы ES6 не интегрированы с фреймворком AngularJS. Только операции, которые применяются в контексте выполнения AngularJS, получат выгоду от привязки данных AngularJS, обработки исключений, наблюдения за свойствами и т. д. Используйте $q.all с фреймворком AngularJS. 21.08.2018

Ответы:


1

Ключ в том, чтобы использовать $q.all и Array.prototype.map

gatherPicture(hierarchy)
.then(() => {
    console.log("I want to wait before doing this!")
})

function gatherPicture(person) {
    // api request (promise)
    return getPicture(person.id).then(r => {
        person.picture = r;
        return  $q.all(person.children.map(gatherPicture));
    }) 
}

Итак, прежде всего верните цепочку промисов, которую вы начинаете с getPicture, из gatherPicture, чтобы вы могли создать правильную цепочку промисов.

Затем вы создаете список промисов для всех дочерних элементов, используя person.children.map(gatherPicture), а затем ждете, пока он разрешится, используя Promise.all.

21.08.2018
  • Большое спасибо за разъяснение того, что важно использовать .map в этой ситуации, чтобы правильно связать их. 21.08.2018
  • @ В заключение, дополнительное примечание: у этого подхода есть один недостаток: он начнет начальную загрузку всех дочерних элементов в одновременное время (JavaScript не является многопоточным), но загрузки могут быть. 21.08.2018
  • @Summy, возможно, вы захотите попробовать это с версией AngularJS: $q.all() 21.08.2018

  • 2

    Другой подход может заключаться в том, чтобы сначала сгладить дерево:

    const flatten = (tree) => (tree.children || [])
      .reduce((flattened, child) => flattened.concat(flatten(child)), [])
      .concat(tree);
    

    Затем, учитывая простую функцию gatherPicture:

    const gatherPicture = (person) => getPicture(person.id).then((picture) => {
      person.picture = picture;
    });
    

    Вы можете легко дождаться их завершения одновременно:

    const gatherPictures = (tree) => Promise.all(flatten(tree).map(gatherPicture));
    

    Использовать:

    gatherPictures(hierarchy).then(() => {
      console.log("Done");
    });
    
    21.08.2018
  • В ответе здесь используются общие обещания ES6. Имейте в виду, что промисы ES6 не интегрированы с фреймворком AngularJS. Только операции, которые применяются в контексте выполнения AngularJS, получат выгоду от привязки данных AngularJS, обработки исключений, наблюдения за свойствами и т. д. Используйте $q.all с фреймворком AngularJS. 21.08.2018

  • 3
  • В ответе здесь используются общие обещания ES6. Имейте в виду, что промисы ES6 не интегрированы с фреймворком AngularJS. Только операции, которые применяются в контексте выполнения AngularJS, получат выгоду от привязки данных AngularJS, обработки исключений, наблюдения за свойствами и т. д. Используйте $q.all с фреймворком AngularJS. 21.08.2018
  • Новые материалы

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..


    Для любых предложений по сайту: [email protected]