为什么带有数组过滤器的Promise.all会导致一个空数组?

时间:2018-12-11 10:53:55

标签: javascript arrays filter promise

我写了一个函数来过滤数组中的时间间隔。 该功能似乎正常工作,并且打印跳过和接受是适当的,并且打印没有错误。 但是,它导致一个空数组。 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);
            });        
        });
    });
}

我也尝试使用.then() on Promise.all进行sligth变体,但无济于事。

我在做什么错? 谢谢, 詹斯

1 个答案:

答案 0 :(得分:4)

因此,您的代码存在一些问题。

首先,您的实际问题。请注意,filter返回一个新数组,其中包含通过测试功能的元素。为了通过测试函数,在该函数的迭代中返回的任何真值都将意味着数组中该索引处的项目应通过。因此,您有:

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

您的第一个直接问题是您没有在过滤器的回调函数中返回任何内容,这意味着您在过滤器的每次迭代中都返回undefinedundefined == false,因此该次迭代不会通过测试。由于没有一项测试通过,因此您最终要得到的是:

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

实际上将解析为undefined的数组。

现在我们已经解决了这个问题,让我们清理一下整个代码。首先,由于您正在使用async,因此几乎永远不需要使用new Promise。将函数标记为async会隐式地将其返回的内容包装在promise中,这意味着您不需要这样做。

// 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,还需要使用filtermap

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;
        }
    });     
}

享受:)

*我不保证我不会在某个地方缺少闭括号或括号:)