Попытка ожидания элементов объекта в цикле - PullRequest
0 голосов
/ 09 октября 2018

Я звоню в API, который возвращает список полей.Некоторые из этих полей имеют связанные поля, которые мне нужно запросить в API, чтобы получить эти поля.

Итак, вот что я пытаюсь сделать (в основном псевдокод):

// gets initial set of fields. This part works.
let fields = await getFields();
processFields(fields).then(data => {
    console.log('data now contains object with all fields and related fields', data);
});

async function processFields(fields) {
    let fieldObj = {};

    return new Promise(resolve => {
        fields.forEach(async field => {
            if (field.collection) {
                let related = await getRelated(field.relatedListFieldType);
                fieldObj[field.id] = {
                    name: field.name,
                    display: field.display,
                    fields: related
                };
            } else {
                fieldObj[field.id] = {name: field.name, display: field.display};
            }
        });

        resolve(fieldObj);
    });
}

async function getRelated(name) {
    … some code here and return promise …
}

Проблема, с которой я сталкиваюсь, заключается в том, что forEach не ждет, поэтому при первом включении console.log я получаю все ожидаемые результаты, кроме полей, в которых есть коллекция.Так как я жду их, он никогда не попадет в возвращенное полеObj.Если я не жду там, я получаю их в поле Obj, но когда я распечатываю их, они просто обещания.Я безуспешно пытался использовать bluebird и библиотеку async npm, чтобы попытаться получить foreach, который будет ждать результатов перед разрешением, но мне это не удалось.Что я могу сделать, чтобы пройти через это?

Редактировать с новым кодом:

async function processFields(data) {

    let fieldObj = {};

    for (let field of data.data) {
        if (field.isCollection) {
            let related = await getRelated(field.relatedListFieldType);
            fieldObj[field.id] = {
                name: field.name,
                display: field.display,
                fields: related
            };
        } else {
            fieldObj[field.id] = {
                name: field.name,
                display: field.display
            }
        }
    }

    return fieldObj;
}

async function getRelated(name) {
    let relatedData = '';

    name = name.toLowerCase();
    if (objects[name]) {
        return objects[name];
    } else {
        // put a placeholder here so we only request this once
        objects[name] = {};
    }

    return new Promise(resolve => {
        let relatedOptions = Object.assign(options, {
            path: encodeURI(`/api/objects/v1/${name}/_describe`)
        });

        let req = https.request(relatedOptions, res => {
            res.on('data', chunk => {
                relatedData += chunk;
            });

            res.on('error', err => {
                console.log('had error', err);
            });

            res.on('end', async () => {
                objects[name] = await processFields(JSON.parse(relatedData));
                resolve(objects[name]);
            });
        });

        req.end();
    });
}

Ответы [ 3 ]

0 голосов
/ 09 октября 2018

fields.forEach не ожидает обещаний, поэтому вы решаете до того, как какой-либо асинхронный код завершитсялибо

async function processFields(fields) {
    let fieldObj = {};

    for (let field of fields) {
        if (field.collection) {
            let related = await getRelated(field.relatedListFieldType);
            fieldObj[field.id] = {
                name: field.name,
                display: field.display,
                fields: related
            };
        } else {
            fieldObj[field.id] = {name: field.name, display: field.display};
        }
    }
    return fieldObj;
}
0 голосов
/ 09 октября 2018

Используйте for, а не .forEach(), чтобы заставить цикл ждать с await..forEach() не предназначен для паузы с await.

Также нет причин создавать свои собственные обещания.Функция async уже возвращает обещание, поэтому вы можете просто использовать await, а затем вернуть значение, которое автоматически станет разрешенным значением возвращенного обещания async.

Например, вы можете сделать этокак это:

async function processFields(fields) {
    let fieldObj = {};

    for (let field of fields) {
        if (field.collection) {
            let related = await getRelated(field.relatedListFieldType);
            fieldObj[field.id] = {
                name: field.name,
                display: field.display,
                fields: related
            };
        } else {
            fieldObj[field.id] = {name: field.name, display: field.display};
        }
    }
    return fieldObj;
}
0 голосов
/ 09 октября 2018
async function processFields(fields) {
    let fieldObj = {};

    for(var field of fields) {
        if (field.collection) {
                let related = await getRelated(field.relatedListFieldType);
                fieldObj[field.id] = {
                    name: field.name,
                    display: field.display,
                    fields: related
                };
            } else {
                fieldObj[field.id] = {name: field.name, display: field.display};
            }
    }
    return fieldObj;
}
...