我正在尝试过滤一组对象。在我过滤之前,我需要将它们转换为某种格式,并且此操作是异步的。
const convert = () => new Promise( resolve => {
setTimeout( resolve, 1000 );
});
所以,我的第一次尝试是使用async / await执行类似下面的操作:
const objs = [ { id: 1, data: "hello" }, { id: 2, data: "world"} ];
objs.filter( async ( obj ) => {
await convert();
return obj.data === "hello";
});
现在,正如你们中的一些人所知,Array.protoype.filter
是一个回调必须返回true或false 的函数。 filter
是同步的。在前面的例子中,我没有返回它们,我返回一个Promise(所有异步函数都是Promises)。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
正如人们可以假设的那样,以前的代码并没有真正起作用......这个假设是正确的。
为了使过滤器能够使用异步函数,我检查了stackoverflow并找到了这个主题:
Filtering an array with a function that returns a promise
不幸的是,所选择的答案过于复杂并且使用了类。这不会对我有用。我正在寻找一个更简单的解决方案,使用功能方法的简单功能。
最后有一个解决方案,使用带回调的地图来模拟过滤器:
https://stackoverflow.com/a/46842181/1337392
但我希望修复我的过滤功能,而不是替换它。
答案 0 :(得分:17)
无法使用具有异步功能的过滤器(至少我知道)。
使用带有promise集合的过滤器的最简单方法是使用Promise.all
,然后将该函数应用于结果集合。
它看起来像这样:
const results = await Promise.all(your_promises)
const filtered_results = results.filter(res => //do your filtering here)
希望它有所帮助。
答案 1 :(得分:1)
使用Scramjet fromArray / toArray方法......
const result = await scramjet.fromArray(arr)
.filter(async (item) => somePromiseReturningMethod(item))
.toArray();
就这么简单 - 这是一个复制/粘贴的现成例子:
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:我是scramjet的作者。 :)
答案 2 :(得分:0)
为要在其上调用filter的数组构建一个并行数组。
在您的过滤器功能中,例如在isValid
中,等待所有的承诺。
在filter
中的回调中,使用第二个参数index索引到并行数组中,以确定是否应对其进行过滤。
// ===============================================
// common
// ===============================================
const isValid = async () => Math.random() > 0.5;
const values = Array(100).fill(42); // array of size 100 with all its values being 42
// ===============================================
// won't filter anything
// ===============================================
const filtered = values.filter(async v => await isValid());
console.log(filtered.length);
// ===============================================
// filters
// ===============================================
(async () => {
const shouldFilter = await Promise.all(values.map(isValid));
const filtered2 = values.filter((value, index) => shouldFilter[index]);
console.log(filtered2.length);
})();
这种行为是有道理的,因为任何Promise
实例都具有真实值,但乍看之下并不直观。
答案 3 :(得分:0)
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(...)
答案 4 :(得分:0)
我只能说这个人TamásSallai很好地解释了这一点:基本上,您执行2个功能:
文章:https://advancedweb.hu/how-to-use-async-functions-with-array-filter-in-javascript/