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

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

我还在 Promise.all 上使用 .then() 尝试了一个小小的变体,但没有成功。

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

最佳答案

所以,您的代码存在一些问题。

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

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

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

await Promise.all([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;       
}

好多了。但是好吧,让我们再次讨论您的问题的核心:您想要过滤掉 promise 列表。这意味着你不能只使用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;
        }
    });     
}

享受吧:)

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

关于javascript - 为什么使用数组过滤器的 Promise.all 会产生空数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53722573/

相关文章:

JavaScript:如何创建对象并过滤这些属性?

javascript - 如何存储 Monoidal List 功能链的数据?

javascript - Jquery 在音频播放时添加类,在不播放音频时删除类

c - 全局结构的数组元素在不一致的位置

javascript - 如何使用多个链接过滤 AngularJS 中的列表

.net - 如何使用 LINQ 查询作为数据源来过滤 BindingSource

javascript - Bootstrap - 多个可忽略的警报

javascript - 来自 Javascript 数组的 Html 表

java - 将带有表情符号的字符串映射到 Array<String|Char>

javascript - 单击一个元素并将其从数组中删除