Uncaught (в обещании) TypeError: невозможно прочитать свойство «длина» неопределенного в promiseKey.then

Я пытаюсь вернуть массив переданных данных из обещания, а затем несколько раз выполнить цикл, чтобы заполнить все данные. Например, у меня есть список брендов и функция, которая принимает параметр бренда и возвращает массив переданных данных.

var datasetarr = [];
brandlist = ['Bh', 'Ruffles'];

let promiseKey = new Promise((resolve, reject) => {
    for(var i = 0; i < brandlist.length; i++){
        datasetarr = populateData(brandlist[i], datasetarr);
    }
    resolve(datasetarr);
});

promiseKey.then((arr) => {
    console.log('complete promise');
    for(var i = 0; i < arr.length; i++){
        console.log(arr[i].date + ' ' + arr[i].total);
    }
});

Сообщение об ошибке

Uncaught (in promise) TypeError: Cannot read property 'length' of undefined
    at promiseKey.then

У меня нет проблем с получением данных, так как мне удалось распечатать детали. Это означает, что обещание не разрешается должным образом. Это правильный способ вернуть массив из обещания? Я не уверен, какая часть была неправильной.


person BlackMamba    schedule 16.08.2017    source источник
comment
promise не определено   -  person guest271314    schedule 16.08.2017
comment
да, я тоже не нашел обещания.   -  person tibetty    schedule 16.08.2017
comment
обратите внимание, let promiseKey = ... почти сразу же преобразуется в undefined, потому что populateData ничего не возвращает   -  person Jaromanda X    schedule 16.08.2017
comment
@JaromandaX Я удивлен ошибкой, которую вы получаете См. исходный пост. promise не был определен. После редактирования datasetarr все еще не определено в .then()   -  person guest271314    schedule 16.08.2017
comment
нет, я понимаю, почему datasetarr равно undefined, потому что populateData возвращает undefined, а populateData потерпит неудачу во второй раз, потому что datasetarr.push потерпит неудачу, так как dataserarr аргумент будет undefined во второй раз   -  person Jaromanda X    schedule 16.08.2017
comment
@JaromandaX Вы читали исходный пост?   -  person guest271314    schedule 16.08.2017
comment
@guest271314 @guest271314 - да, я умею читать код, спасибо за беспокойство :p   -  person Jaromanda X    schedule 16.08.2017
comment
Вы хотели назначить datasetarr[i] = … в этом цикле?   -  person Bergi    schedule 16.08.2017
comment
@Bergi Когда я вызываю populateData(), он должен возвращать массив, отфильтрованный по параметру бренда. Затем я хотел добавить этот массив, возвращенный в набор данных, и выполнить цикл до конца списка брендов.   -  person BlackMamba    schedule 16.08.2017
comment
@DeniseTan Прежде всего, вы должны понимать, что вы не можете вернуть массив из populateData, но в лучшем случае это обещание.   -  person Bergi    schedule 16.08.2017
comment
@Bergi Извините, но как мне получить доступ к массиву из возвращенного обещания?   -  person BlackMamba    schedule 16.08.2017
comment
@JaromandaX Есть ли способ вернуть массив из обещания или получить доступ к возвращаемому массиву из возвращенного обещания?   -  person BlackMamba    schedule 16.08.2017
comment
@DeniseTan Во-первых, вы даже не вернули обещание :-) Посмотрите мой ответ, как бы я это сделал.   -  person Bergi    schedule 16.08.2017


Ответы (2)


Во-первых, ваш populateData должен возвращать обещание — в этом случае это будет разрешенный массив обещаний, созданный в data.forEach.

var brandlist = ['Bh', 'Ruffles'];

let promiseKey = Promise.all(brandlist.map(brand => populateData(brand)))
.then(results => [].concat(...results)); // flatten the array of arrays

promiseKey.then((arr) => {
    console.log('complete promise');
    for(var i = 0; i < arr.length; i++){
        console.log(arr[i].date + ' ' + arr[i].total);
    }
});

function populateData(brand, datasetarr) {
    console.log('go in');
    var query;// = // query by brand parameter
    return query.once('value').then(data => {
        var promises = [];
        data.forEach(snapshot => {
            // get each receipt item details

            // get receipt details by receipt ID
            var query;// = // query receipts
            promises.push(query.once('value').then(data => { 
                // removed code
                // managed to print out here so data fetching is not a problem
                console.log(brand + ' ' + date + ' ' + itemTotal);
                return {date: date, total: itemTotal};
            })); 
        }); 
        return Promise.all(promises);
    });
}

Или, используя функцию snapshotToArray, которую я дал вам в этом ответе неделю назад

const snapshotToArray = snapshot => {
    const ret = [];
    snapshot.forEach(childSnapshot => {
        ret.push(childSnapshot);
    });
    return ret;
};

function populateData(brand, datasetarr) {
    console.log('go in');
    var query;// = // query by brand parameter
    return query.once('value').then(data => Promise.all(snapshotToArray(data).map(snapshot => {
        // get each receipt item details

        // get receipt details by receipt ID
        var query;// = // query receipts
        return query.once('value').then(data => { 
            // removed code
            // managed to print out here so data fetching is not a problem
            console.log(brand + ' ' + date + ' ' + itemTotal);
            return {date: date, total: itemTotal};
        }); 
    }))); 
}
person Jaromanda X    schedule 16.08.2017
comment
нет, вы ничего не перепутали. Этот пользователь задал этот более сложный вопрос неделю назад. Я надеялся, что они воспользуются некоторыми приемами из ответа, но, очевидно, они этого не сделали, потому что этот код страдает почти таким же недостатком понимания, как и код на прошлой неделе. - person Jaromanda X; 16.08.2017
comment
на прошлой неделе были некоторые условные операторы, которые привели к undefined элементам массива, поэтому была выполнена эта неприятная фильтрация: p Я говорю неприятная, потому что я думаю, что я злоупотреблял .filter, если честно - person Jaromanda X; 16.08.2017

Хотя можно работать с глобальной datasetarray переменной, к которой вы push можете обращаться из любого места, я бы не рекомендовал этого делать. Вместо этого напишите метод getData, который возвращает (обещание) массив, и после его многократного вызова (по одному разу для каждого бренда) вы объединяете их вместе.

const brandlist = ['Bh', 'Ruffles'];
const promiseKey = Promise.all(brandlist.map(getData)).then(arrays => [].concat(...arrays));
promiseKey.then(arr => {
    console.log('complete promise');
    for (const item of arr)
        console.log(item.date + ' ' + item.total);
});

function getData(brand) { // no array parameter!
    console.log('go in');
    const query = …; // query by brand parameter
    return query.once('value').then(data => {
        const promises = toArray(data).map(snapshot => {
        const query = …; // get receipt item details by receipt ID
        return query.once('value').then(data => { 
            …
            return {date: date, total: itemTotal}; // don't push, just return the result
        });
        return Promise.all(promises); // resolves with an array of results
    }); // resolves with that same result array
}
function toArray(forEachable) {
    const arr = [];
    forEachable.forEach(x => { arr.push(x); });
    return arr;
}
person Bergi    schedule 16.08.2017
comment
Он сказал мне, что data.map не является функцией в этой строке: const promises = data.map(snapshot =› { - person BlackMamba; 16.08.2017
comment
Я думаю, вы попались в ловушку data.map - данные не являются массивом: p - person Jaromanda X; 16.08.2017
comment
Мне больше нравится ваша функция toArray, потому что ее имя является общим :p - person Jaromanda X; 16.08.2017