为什么使用数组过滤器的 Promise.all 会产生空数组?

jal*_*mer 0 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);
            });        
        });
    });
}
Run Code Online (Sandbox Code Playgroud)

我也尝试过使用一个小的变体.then() on Promise.all,但没有成功。

我究竟做错了什么?谢谢你,延斯

Mat*_*bst 5

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

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

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

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

await Promise.all([undefined, undefined, ...])
Run Code Online (Sandbox Code Playgroud)

这确实会解析为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;
        });        
    });
}
Run Code Online (Sandbox Code Playgroud)

好吧,接下来,既然你在async世界上,你永远不需要使用.thenor .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;       
}
Run Code Online (Sandbox Code Playgroud)

好多了。但是好吧,让我们再次讨论您的问题的核心:您想要过滤掉承诺列表。这意味着您不仅可以使用filter,还需要使用filterand 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;
        }
    });     
}
Run Code Online (Sandbox Code Playgroud)

享受 :)

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