Как вернуть обещание из рекурсивного метода - PullRequest
0 голосов
/ 28 мая 2018

На самом деле я работаю с Firebase в проекте Javascript и пытаюсь получить информацию о вложенных дочерних элементах всех элементов в коллекциях.

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

Для этой статьи я создал фальшивый метод, демонстрирующий мою реальную логику.Может быть, кто-то может мне помочь, это бесконечный цикл, который запускает последний элемент бесконечно.В нем никогда не сохраняются первые результаты

function fakeWait(toReturn) {
  return new Promise((resolve) => {
    setTimeout(function(){ resolve(toReturn); }, 8000);
  });
}

function callMe(params = null) {
  return new Promise((resolve, reject) => {
   console.log('Promise called', {...params});

    const promises = [];

    if (params === null) {
      promises.push(fakeWait(
        {
          id1:{title:'Title1'},
          id2:{title:'Title2'},
          id3:{title:'Title3'},
          id4:{title:'Title4'},
        }).then(results => {
          params = {};
          params.formations = results;
          resolve(callMe(params));
        }));
    }

    else {
      if (!params.hasOwnProperty('formationId') && 
          params.hasOwnProperty('formations')) {
        Object.keys(params.formations).forEach(formationId => {
          params.formationId = formationId;
          promises.push(resolve(callMe(params)));
        });
            }

      else if (params.hasOwnProperty('formationId') && 
               params.hasOwnProperty('formations') && 
               !params.formations[params.formationId].hasOwnProperty.modules) 
      {
        promises.push(fakeWait({
          id1:{title:'Title1.1'},
          id2:{title:'Title1.2'},
          id3:{title:'Title1.3'},
          id4:{title:'Title1.4'},
        }).then(result => {
          params.formations[params.formationId].modules = result;
          resolve(callMe(params));
        }))
            }
    }

    Promise.all(promises).then(() => { console.log('Resolved.'); resolve(params); }).catch(()=> reject('oops'));
  });
}

callMe().then(results =>console.log(results)).catch(msg => console.log(msg));

Вы также можете просмотреть и попробовать код на стеке: https://stackblitz.com/edit/js-wuvp9z

Структура данных Firebase:

Formations - Collection
- Formation - Document
-- Modules - Collection
--- Module - Document
---- Chapters - Collection
----- Chapter - Document
------ Screens - Collection
------- Screen - Document

1 Ответ

0 голосов
/ 30 мая 2018

Вот код транзакции Firestore, которая запишет новый документ Screen и обновит счетчики nbrScreens в родительских документах Formation, Module и Chapter соответственно.

Это полная HTML-страница,Выполните следующие действия:

1 / Адаптируйте значения конфигурации Firebase в HTML.

2 / Создайте в Firestore родительские коллекции и документы с нужными идентификаторами.

3 / Для каждого документа (формация, модуль и глава) добавьте поле типа номер с именем nbrScreens со значением 0

4 / Адаптируйте на странице HTML значение screenId, screenData и параметры функции setNewScreen() вызывают то, что вам нужно.

5 / Откройте страницу в браузере (например, локально), функция будет вызвана и транзакция выполнена

<!DOCTYPE html>
<html lang="en">
<head>
    <script src="https://www.gstatic.com/firebasejs/5.0.4/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/5.0.4/firebase-firestore.js"></script>
</head>

<body>

<script>

    var config = {
        apiKey: "...",
        authDomain: "...",
        databaseURL: "...",
        projectId: "..."
    };

    firebase.initializeApp(config);

    var firestoredb = firebase.firestore();


    function setNewScreen(formationId, moduleId, chapterId, screenId, screenData) {

        var formationDocRef = firestoredb.collection("Formations").doc(formationId);
        var moduleDocRef = formationDocRef.collection("Modules").doc(moduleId);
        var chapterDocRef = moduleDocRef.collection("Chapters").doc(chapterId);
        var screenDocRef = chapterDocRef.collection("Screens").doc(screenId);

        return firestoredb.runTransaction(function (transaction) {

            var newChaptersNbrScreens;
            var newModulesNbrScreens;
            var newFormationsNbrScreens;

            return transaction.get(chapterDocRef)
                .then(function (sfDoc) {

                    if (!sfDoc.exists) {
                        throw "Document Chapter does not exist!";
                    }

                    newChaptersNbrScreens = sfDoc.data().nbrScreens + 1;
                    return transaction.get(moduleDocRef);

                })
                .then(function (sfDoc) {

                    if (!sfDoc.exists) {
                        throw "Document Module does not exist!";
                    }

                    newModulesNbrScreens = sfDoc.data().nbrScreens + 1;
                    return transaction.get(formationDocRef);

                })
                .then(function (sfDoc) {

                    if (!sfDoc.exists) {
                        throw "Document Formation does not exist!";
                    }

                    newFormationsNbrScreens = sfDoc.data().nbrScreens + 1;
                    return transaction
                        .set(formationDocRef, {nbrScreens: newFormationsNbrScreens}, { merge: true })
                        .set(moduleDocRef, {nbrScreens: newModulesNbrScreens}, { merge: true })
                        .set(chapterDocRef, {nbrScreens: newChaptersNbrScreens}, { merge: true })
                        .set(screenDocRef, screenData)

                });

        });

    }


    //Calling the function
    //The formation, module and chapter docs must be created before calling it!!

    var screenId = 's1';
    var screenData = {title: 'screenTitle_s1', content: 'foo'};

    setNewScreen("f1", "m1", "c1", screenId, screenData)  //Screen will be saved under Formation f1, Module m1 and Chapter c1
        .then(function () {
            console.log("Transaction successfully committed!");
        })
        .catch(function (error) {
            console.log("Transaction failed: ", error);
        });


</script>


</body>
</html>

Обратите внимание, что вы можете адаптировать код для создания Формации, Модуля и Главы.На самом деле это не может быть сделано в транзакции , потому что все операции чтения должны выполняться до записи (записей) .

. Вы могли бы что-то вроде (псевдокод):

FormationDocumentReference.set({}) // <- returns a promise
.then(function() {
    ModuleDocumentReference.set({}) // <- returns a promise
})
.then(function() {
    ChapterDocumentReference.set({}) // <- returns a promise
})
.then(function() {
    setNewScreen(id_f, id_m1, id_c1, screenId, screenData)  // <- returns a promise
.then(function () {
    console.log("Transaction successfully committed!");
})
.catch(function (error) {
    console.log("Transaction failed: ", error);
});

Наконец, вот пара примечательных моментов, касающихся приведенного выше кода транзакции:

1 / transaction.get() возвращает обещание, содержащее ненулевое firebase.firestore.DocumentSnapshot, как объяснено здесь .Поэтому вы должны связать их с помощью then().

2 / С другой стороны, transaction.set() возвращает «Этот экземпляр транзакции», см. здесь .Поэтому вы должны просто цеплять их один за другим (например, return transaction.set().set()...)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...