Array.prototype.every异步返回false但整体判定为true的问题排查
问题分析与修复方案
你的原代码
return Dex.mod('gen9').species.all() .filter(pkmn => pkmn.isNonstandard === null) .filter(async pkmn => { const gens = new Generations(Dex); console.log(moveList.every(async (move) => gens.get(9).learnsets.canLearn(pkmn.name, move))); return moveList.every(async (move) => { console.log(pkmn.name, move, await gens.get(9).learnsets.canLearn(pkmn.name, move)); await gens.get(9).learnsets.canLearn(pkmn.name, move) }); });
问题根源
Array.every配异步回调的坑:every是同步方法,它会直接判断回调返回的值是否为真。但你传的是async回调,这类回调返回的永远是Promise对象,而Promise在布尔判断里属于真值——不管异步结果是true还是false,every都会认为所有回调都通过,所以整体返回true,这就是单个console.log能看到false但every结果是true的原因。Array.filter配异步回调的坑:filter同样是同步方法,它需要回调返回布尔值。但async回调返回的是Promise,所有Promise都会被当成true,导致过滤完全失效,所以你会得到700+结果,而不是预期的42个。
修复后的代码
// 先同步过滤出非标准形态的精灵,减少后续异步操作量 const baseSpecies = Dex.mod('gen9').species.all() .filter(pkmn => pkmn.isNonstandard === null); // 异步处理过滤逻辑 const filteredSpecies = await Promise.all( baseSpecies.map(async pkmn => { const gens = new Generations(Dex); // 批量获取所有招式的学习判定结果 const learnResults = await Promise.all( moveList.map(move => gens.get(9).learnsets.canLearn(pkmn.name, move)) ); // 用同步的every判断是否所有招式都能学习 const canLearnAll = learnResults.every(result => result); // 调试用:输出不能学习全部招式的精灵和对应的招式 if (!canLearnAll) { const unlearnable = moveList.filter((move, idx) => !learnResults[idx]); console.log(`${pkmn.name} 学不会这些招式:`, unlearnable); } return { pkmn, canLearnAll }; }) ) // 过滤出符合条件的精灵 .filter(item => item.canLearnAll) .map(item => item.pkmn); return filteredSpecies;
修复思路说明
- 先做同步过滤,把明显不符合条件的精灵排除,避免没必要的异步请求
- 用
Promise.all批量处理所有招式的异步判定,并行执行提升效率 - 拿到所有异步结果的数组后,用同步的
every判断是否全部为true,保证逻辑正确 - 最后再用同步的
filter筛选出符合条件的精灵,确保filter拿到的是布尔值
内容的提问来源于stack exchange,提问作者Toomuchbob
相关产品推荐
相关产品推荐

