Почему Promise.all с фильтром массива приводит к пустому массиву? - PullRequest
0 голосов
/ 11 декабря 2018

Я написал функцию для фильтрации временного интервала из массива.Кажется, что функция работает, и печати пропускаются и принимают, и они печатаются без ошибок.Однако это приводит к пустому массиву.getDate() - это функция, которая возвращает дату, чтобы ее можно было преобразовать во время, используя getTime().Это работает.

async function getInterval(climatedata,harvestdate,period) { 
    return new Promise(function(resolve, reject) {    
        getDate(harvestdate,-1*period).then((sval)=>{
            let start = sval.getTime();
            getDate(harvestdate,0).then(async(eval)=>{
                let end = eval.getTime();
                let filtered = await Promise.all(climatedata.filter((curVal,index,arr) => {
                    getDate(curVal[0]).then((tval)=>{
                        let td = tval.getTime();
                        //console.log(start,td,end);
                        if(td >= start && td <= end) {   
                            console.log("accept"); //although this is printed for the expected subset, nothing is in the filtered array.
                            return true;
                        } else {
                            //console.log("skip");
                            return false;
                        }                    
                    }).catch((err)=>{console.log(err);});
                }));    
                console.log("filtered",filtered); //here I would expect an array with some rows.
                //console.log("bef",climatedata.length,"aft",filtered.length); //this is always bef 8000 aft 0
                resolve(filtered);
            });        
        });
    });
}

Я также попробовал вариант sligth, используя .then() on Promise.all, но безрезультатно.

Что я делаю не так?Спасибо, Дженс

1 Ответ

0 голосов
/ 11 декабря 2018

Итак, есть несколько проблем с вашим кодом.

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

await Promise.all(climatedata.filter((curVal,index,arr) => {
  getDate(curVal[0])...
};

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

await Promise.all([undefined, undefined, ...])

, который действительно разрешится в массив undefined.

Теперь, когда мы получили это изКстати, давайте очистим ваш код целой кучей.Во-первых, поскольку вы используете async, вам почти никогда не нужно использовать new Promise.Пометка функции как async неявно оборачивает все, что она возвращает, в обещании, то есть вам не нужно.

// NOTE: I've removed your console.log statements to make it simpler to read
async function getInterval(climatedata,harvestdate,period) {   
    return getDate(harvestdate,-1*period).then((sval)=>{
        let start = sval.getTime();
        getDate(harvestdate,0).then(async(eval)=>{
            let end = eval.getTime();
            let filtered = await Promise.all(climatedata.filter((curVal,index,arr) => {
                return getDate(curVal[0]).then((tval)=>{ // NOTICE: I added `return` here to beging to fix your filter problem
                    let td = tval.getTime();
                    if(td >= start && td <= end) {   
                        return true;
                    } else {
                        return false;
                    }                    
                }).catch((err)=>{console.log(err);});
            }));

            return filtered;
        });        
    });
}

Хорошо, далее, поскольку вы находитесь в мире async, вам никогда не понадобитсяиспользовать .then или .catch:

async function getInterval(climatedata, harvestdate, period) {
    let sval;

    try {
        sval = await getDate(harvestdate, -1 * period);
    } catch (error) {
        console.log('getting `sval` failed, oh no!');
        throw error;
    }

    let start = sval.getTime();
    let eval;

    try {
        eval = await getDate(harvestdate, 0);
    } catch (error) {
        console.log('getting `eval` failed, oh no!');
        throw error;
    }

    let end = eval.getTime();
    let filtered = await Promise.all(climatedata.filter(async (curVal,index,arr) => {
        let tval;

        try {
            tval = getDate(curVal[0]);
        } catch (error) {
            console.log('getting `tval` failed, oh no!');
            throw error;
        }

        let td = tval.getTime();
        if(td >= start && td <= end) {   
            return true;
        } else {
            return false;
        }
    })); 

    return filtered;       
}

Так намного приятнее.Но ладно, давайте вернемся к сути вашей проблемы: вы хотите отфильтровать список обещаний.Это означает, что вы не можете использовать только filter, вам нужно использовать filter и map:

async function getInterval(climatedata, harvestdate, period) {
    let sval;

    try {
        sval = await getDate(harvestdate, -1 * period);
    } catch (error) {
        console.log('getting `sval` failed, oh no!');
        throw error;
    }

    let start = sval.getTime();
    let eval;

    try {
        eval = await getDate(harvestdate, 0);
    } catch (error) {
        console.log('getting `eval` failed, oh no!');
        throw error;
    }

    let end = eval.getTime();

    const filterTest = (curVal, index, arr)

    const climatedataPromises = climatedata.map(curVal => getDate(curVal[0])); // Create a list of promises
    const climatedata = await Promise.all(climatedataPromises); // Wait for them all to return

    return climatedata.filter((tval, index) => { // Now run your filter
        let td = tval.getTime();

        if(td >= start && td <= end) {   
            return true;
        } else {
            return false;
        }
    });     
}

Наслаждайтесь:)

* Я не обещаю, что яЯ не пропускаю закрывающую скобку или скобку где-то там:)

...