javascript 如何将 Array.prototype.filter 与异步一起使用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/47095019/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use Array.prototype.filter with async?
提问by Flame_Phoenix
Background
背景
I am trying to filter an array of objects. Before I filter, I need to convert them to some format, and this operation is asynchronous.
我正在尝试过滤一组对象。在过滤之前,我需要将它们转换为某种格式,并且此操作是异步的。
const convert = () => new Promise( resolve => {
setTimeout( resolve, 1000 );
});
So, my first try was to do something like the following using async/await:
因此,我的第一次尝试是使用 async/await 执行以下操作:
const objs = [ { id: 1, data: "hello" }, { id: 2, data: "world"} ];
objs.filter( async ( obj ) => {
await convert();
return obj.data === "hello";
});
Now, as some of you may know, Array.protoype.filteris a function which callback must return either true or false. filteris synchronous. In the previous example, I am returning none of them, I return a Promise ( all async functions are Promises ).
现在,正如你们中的一些人可能知道的那样,Array.protoype.filter回调必须返回 true 或 false的函数。filter是同步的。在前面的例子中,我没有返回它们,我返回一个 Promise (所有异步函数都是 Promises )。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
So as one can assume, the code before doesn't really work... That assumption is correct.
因此,可以假设,之前的代码并不能真正起作用……这种假设是正确的。
Problem
问题
To make filter work with an async function, I checked stackoverflow and found this topic:
为了使过滤器与异步函数一起工作,我检查了 stackoverflow 并找到了这个主题:
Filtering an array with a function that returns a promise
Unfortunately, the chosen answer is overly complex and uses classes. This won't do for me. I am instead looking for a more simple solution, using simple functions with a functional approach.
不幸的是,选择的答案过于复杂并且使用了类。这对我不起作用。相反,我正在寻找一个更简单的解决方案,使用简单的函数和函数式方法。
There is one solution at the very end, using a map with a callback to simulate a filter:
最后有一个解决方案,使用带有回调的映射来模拟过滤器:
https://stackoverflow.com/a/46842181/1337392
https://stackoverflow.com/a/46842181/1337392
But I was hoping to fix my filter function, not to replace it.
但我希望修复我的过滤器功能,而不是更换它。
Questions
问题
- Is there a way to have an async function inside a filter?
- If not, what is the simplest replacement I can do?
- 有没有办法在过滤器中使用异步函数?
- 如果没有,我能做的最简单的替换是什么?
采纳答案by mcousillas
There is no way to use filter with an async function (at least that I know of).
The simplest way that you have to use filter with a collection of promises is to use Promise.alland then apply the function to your collection of results.
It would look something like this:
没有办法将过滤器与异步函数一起使用(至少我知道)。您必须将过滤器与承诺集合一起使用的最简单方法是使用Promise.all该函数并将其应用于您的结果集合。它看起来像这样:
const results = await Promise.all(your_promises)
const filtered_results = results.filter(res => //do your filtering here)
Hope it helps.
希望能帮助到你。
回答by Micha? Kapracki
Use ScramjetfromArray/toArray methods...
使用ScramjetfromArray/toArray 方法...
const result = await scramjet.fromArray(arr)
.filter(async (item) => somePromiseReturningMethod(item))
.toArray();
as simple as that - here's a ready example to copy/paste:
就这么简单 - 这是一个可以复制/粘贴的现成示例:
const scramjet = require('../../');
async function myAsyncFilterFunc(data) {
return new Promise(res => {
process.nextTick(res.bind(null, data % 2));
});
}
async function x() {
const x = await scramjet.fromArray([1,2,3,4,5])
.filter(async (item) => myAsyncFilterFunc(item))
.toArray();
return x;
}
x().then(
(out) => console.log(out),
(err) => (console.error(err), process.exit(3)) // eslint-disable-line
);
Disclamer: I am the author of scramjet. :)
免责声明:我是超燃冲压发动机的作者。:)
回答by user285294
Array.prototype.asyncFilter =function( filterFn) {
const arr = this;
return new Promise(function(resolve){
const booleanArr = [];
arr.forEach(function (e) {
booleanArr.push(filterFn(e))
})
Promise.all(booleanArr).then(function (booleanArr) {
const arr2 = arr.filter(function (e, i) {
return booleanArr[i]
})
resolve(arr2)
})
})
}
/** use it like this**/
const arr=[1,2,3]
arr.asyncFilter(async e=>{}).then(...)
回答by James T.
Build a parallel array to your array which you want to call filter on.
Await all of the promises from your filter func, in my eg, isValid.
In the callback in filter, use the 2nd arg, index, to index into your parallel array to determine if it should be filtered.
为要调用过滤器的数组构建一个并行数组。等待过滤器函数的所有承诺,在我的例子中,isValid. 在 中的回调中filter,使用第二个参数 index 来索引并行数组以确定是否应该对其进行过滤。
// ===============================================
// common
// ===============================================
const isValid = async (value) => value >= 0.5;
const values = [0.2, 0.3, 0.4, 0.5, 0.6];
// ===============================================
// won't filter anything
// ===============================================
const filtered = values.filter(async v => await isValid(v));
console.log(JSON.stringify(filtered));
// ===============================================
// filters
// ===============================================
(async () => {
const shouldFilter = await Promise.all(values.map(isValid));
const filtered2 = values.filter((value, index) => shouldFilter[index]);
console.log(JSON.stringify(filtered2));
})();
This behavior makes sense since any Promiseinstance has a truthy value, but it's not intuitive at a glance.
这种行为是有道理的,因为任何Promise实例都有一个真实的值,但一目了然。

