返回内部块可观察对象
Returning Inner Block Observable Object
我想 return 我的 Firebase 数据库中在过去 7 天内质量评级最高的单个对象。我使用以下 Typescript 代码首先查询过去 7 天创建的所有线程,其次提取 quality
处具有最高值的线程。理想情况下,我可以将 "transform" 可观察到的 results
放入 forEach 语句的最终迭代对象中。
highestWeek: Number = 0;
...
getWeeksBest(): Observable<any> {
let now = Date.now() / 1000;
let results = this.af.database.list('/threads', {
query: {
orderByChild: 'created',
startAt: now - 604800 //One week ago
}
})
.map(results => {
results.forEach(result => {
if (result.quality > this.highestWeek) {
console.log(result) //Logs next highest quality thread
this.highestWeek = result.quality
}
})
})
results.subscribe(results => console.log(results)) //Undefined
return results //Undefined
}
所以问题可能是为什么您在 results
变量的 subscribe(...)
回调中得到 undefined
。
在 .map()
中,您使用短箭头语法创建代码块,但这意味着您必须使用 return
语句。
.map(results => {
results.forEach(result => {
if (result.quality > this.highestWeek) {
console.log(result) //Logs next highest quality thread
this.highestWeek = result.quality
}
});
return results;
})
在你的情况下,我最好使用 .do()
运算符而不是 .map()
。
在 getWeeksBest()
的末尾你返回了 Observable 所以最后一行肯定没有返回 undefined
.
getWeeksBest(): Observable<any> {
let now = Date.now() / 1000;
let results = this.af.database.list('/threads', {
...
});
return results;
}
martin 是对的,您需要添加一个 return
语句。但也要记住 Array.forEach 总是返回 undefined
。所以在你的情况下你可以使用 Array.map
.
但总的来说,我会建议这样的事情:
getAllThreads$(): Observable<any[]> {
let now = Date.now() / 1000;
return this.af.database.list('/threads', {
query: {
orderByChild: 'created',
startAt: now - 604800 //One week ago
}
})
}
getWeeksBest$():Observable<number>{
return this.getAllThreads$().map(threads => Array.isArray(threads )? threads.reduce((highestQuality, thread) => {
let currentQuality = thread? thread.quality: 0;
return currentQuality > highestQuality? currentQuality: highestQuality;
}, 0): 0);
}
并且在您的 class 构造函数中的某处只需订阅 getWeeksBest$
RxJS 提供了大量的操作符来执行数据转换。在您的情况下,您想要检索具有最高 quality
值的对象,因此我们可以使用 reduce 运算符,我们将在其中应用 maxBy()
函数。
const weeks = [
{
quality: 1
},
{
quality: 15
},
{
quality: 5
},
{
quality: 8
}
];
//maxBy stateless function (you can see a currified function)
const maxBy = (prop) => (a, b) => a[prop] > b[prop] ? a : b;
//Fetch data and apply the maxBy when the reduce is perform over the collection
function fetchData() {
//You can perform some async actions
return Rx
.Observable
.from(weeks)
.reduce(maxBy('quality'), 0);
}
fetchData().subscribe(x => console.log(x));
随时查看 Plunker
上的示例
如果你想 return 一个在上周发出质量最高的线程的可观察对象,你传递给 map
运算符的函数需要 return 一个值(如其他答案中所述)。
另外,您需要决定在没有线程的情况下预期的行为。结果观察结果应该是空的吗?或者它应该发出 null
?
可能最好避免内部订阅 - 您将在每次调用时进行额外订阅,并且该订阅永远不会取消订阅。最好也避免 side-effect,因为发出的线程将提供最高质量。
你可以这样做,而不是:
getWeeksBest(): Observable<any> {
let now = Date.now() / 1000;
let best = this.af.database.list('/threads', {
query: {
orderByChild: 'created',
startAt: now - 604800 //One week ago
}
})
// Filter out empty lists of threads, so that the resultant
// observable emits nothing if there are no threads:
.filter(threads => threads.length > 0)
// Use Array.prototype.reduce to return the thread with the
// highest quality:
.map(threads => threads.reduce(
(acc, thread) => thread.quality > acc.quality ? thread : acc
));
return best;
}
如果你想在没有线程的情况下发出 null
,请删除 filter
并将 map
更改为:
.map(threads => (threads.length === 0) ? null : threads.reduce(
(acc, thread) => thread.quality > acc.quality ? thread : acc
))
我想 return 我的 Firebase 数据库中在过去 7 天内质量评级最高的单个对象。我使用以下 Typescript 代码首先查询过去 7 天创建的所有线程,其次提取 quality
处具有最高值的线程。理想情况下,我可以将 "transform" 可观察到的 results
放入 forEach 语句的最终迭代对象中。
highestWeek: Number = 0;
...
getWeeksBest(): Observable<any> {
let now = Date.now() / 1000;
let results = this.af.database.list('/threads', {
query: {
orderByChild: 'created',
startAt: now - 604800 //One week ago
}
})
.map(results => {
results.forEach(result => {
if (result.quality > this.highestWeek) {
console.log(result) //Logs next highest quality thread
this.highestWeek = result.quality
}
})
})
results.subscribe(results => console.log(results)) //Undefined
return results //Undefined
}
所以问题可能是为什么您在 results
变量的 subscribe(...)
回调中得到 undefined
。
在 .map()
中,您使用短箭头语法创建代码块,但这意味着您必须使用 return
语句。
.map(results => {
results.forEach(result => {
if (result.quality > this.highestWeek) {
console.log(result) //Logs next highest quality thread
this.highestWeek = result.quality
}
});
return results;
})
在你的情况下,我最好使用 .do()
运算符而不是 .map()
。
在 getWeeksBest()
的末尾你返回了 Observable 所以最后一行肯定没有返回 undefined
.
getWeeksBest(): Observable<any> {
let now = Date.now() / 1000;
let results = this.af.database.list('/threads', {
...
});
return results;
}
martin 是对的,您需要添加一个 return
语句。但也要记住 Array.forEach 总是返回 undefined
。所以在你的情况下你可以使用 Array.map
.
但总的来说,我会建议这样的事情:
getAllThreads$(): Observable<any[]> {
let now = Date.now() / 1000;
return this.af.database.list('/threads', {
query: {
orderByChild: 'created',
startAt: now - 604800 //One week ago
}
})
}
getWeeksBest$():Observable<number>{
return this.getAllThreads$().map(threads => Array.isArray(threads )? threads.reduce((highestQuality, thread) => {
let currentQuality = thread? thread.quality: 0;
return currentQuality > highestQuality? currentQuality: highestQuality;
}, 0): 0);
}
并且在您的 class 构造函数中的某处只需订阅 getWeeksBest$
RxJS 提供了大量的操作符来执行数据转换。在您的情况下,您想要检索具有最高 quality
值的对象,因此我们可以使用 reduce 运算符,我们将在其中应用 maxBy()
函数。
const weeks = [
{
quality: 1
},
{
quality: 15
},
{
quality: 5
},
{
quality: 8
}
];
//maxBy stateless function (you can see a currified function)
const maxBy = (prop) => (a, b) => a[prop] > b[prop] ? a : b;
//Fetch data and apply the maxBy when the reduce is perform over the collection
function fetchData() {
//You can perform some async actions
return Rx
.Observable
.from(weeks)
.reduce(maxBy('quality'), 0);
}
fetchData().subscribe(x => console.log(x));
随时查看 Plunker
上的示例如果你想 return 一个在上周发出质量最高的线程的可观察对象,你传递给 map
运算符的函数需要 return 一个值(如其他答案中所述)。
另外,您需要决定在没有线程的情况下预期的行为。结果观察结果应该是空的吗?或者它应该发出 null
?
可能最好避免内部订阅 - 您将在每次调用时进行额外订阅,并且该订阅永远不会取消订阅。最好也避免 side-effect,因为发出的线程将提供最高质量。
你可以这样做,而不是:
getWeeksBest(): Observable<any> {
let now = Date.now() / 1000;
let best = this.af.database.list('/threads', {
query: {
orderByChild: 'created',
startAt: now - 604800 //One week ago
}
})
// Filter out empty lists of threads, so that the resultant
// observable emits nothing if there are no threads:
.filter(threads => threads.length > 0)
// Use Array.prototype.reduce to return the thread with the
// highest quality:
.map(threads => threads.reduce(
(acc, thread) => thread.quality > acc.quality ? thread : acc
));
return best;
}
如果你想在没有线程的情况下发出 null
,请删除 filter
并将 map
更改为:
.map(threads => (threads.length === 0) ? null : threads.reduce(
(acc, thread) => thread.quality > acc.quality ? thread : acc
))