我在操作GET请求的结果元素时遇到问题。
正在使用IonicSuper starter template构建应用,并使用该模板中提供的REST API handler。
我似乎无法理解返回结果的类型以及如何操作它。我要说,我对应用程序开发没有多少经验,更不用说TypeScript及其变体了。但我的理解是RxJS提供了一个允许certain operations on the resulting data的Observable数据类型。但是当我使用所述API处理程序时,这些都不起作用 我在各个网站上搜索了解决方案,但没有一个适合。无论我在哪里,基本的Angular HttpClient都与RxJS Observable一起使用。由于我正在使用IonicSuper模板,所以我也想使用包含的REST API处理程序。但是我无法从代码和文档中检索出我需要的信息。
我的目标是从给定id指定的一组对象中获取单个对象(或者:只包含一个对象的数组)。以下是我的provider.ts的相关部分:
import { Injectable } from '@angular/core';
import { Api } from '../api/api';
import 'rxjs/add/operator/filter';
import { tPrediction } from '../../models/prediction';
@Injectable()
export class Prediction {
//API endpoint: Predictions
private epPredictions = 'predictions';
constructor(private api: Api) { }
getPrediction(id: number) {
let seq = this.api
.get(this.epPredictions)
// .flatMap((response) => response.json())
.filter(prediction => prediction.id == id)
.share();
seq.subscribe((res: any) => {
console.debug('prediction id', id);
console.debug('res', res);
}, err => {
this.handleError(err);
});
return seq;
}
}
现在,flatMap()和filter()都会产生TypeScript错误Property '(flatMap|filter)' does not exist on type 'Observable<ArrayBuffer>'.
这就是我迷失的地方:我理解这一点,http.get()返回一个Observable,并且应该使用这些运算符。显然情况并非如此。
我也试过提供一个类似于RxJS docs的函数:
let seq = this.api
.get(this.epPredictions)
// .flatMap((response) => response.json())
.filter(function(prediction, idx) {
console.debug('getPrediction id', id);
console.debug('getPrediction prediction.id', prediction["id"]);
return prediction["id"] == id;
})
.share();
也不起作用,因为prediction["id"]
未定义。
我无法理解 ArrayBuffer 类型的工作原理以及我可以用它做什么。
如果需要其他信息,我会编辑这篇文章。
感谢您阅读本文以及您提供的任何知识。
PS:我知道我可以让服务器通过仅将ID作为额外的GET参数来进行过滤,这最终可能会发生。但是因为这是我试图理解的一个非常基本的问题,我现在想解决这个问题,同时处理我当前的任务。
修改
我制作了一个项目副本并将RxJS软件包更新到版本5.5.10(在5.5.7上)。提供程序现在正在使用.pipe(),但它仍然无法访问 prediction.id ,因为它正在处理ArrayBuffer。
这是当前的getPrediction():
getPrediction(id: number) {
var predictions = this.api.get(this.epPredictions);
console.debug('pipe');
var seq = predictions.pipe(
filter(function(prediction, i){
console.debug('prediction', prediction);
return prediction.id === id;
})
);
seq.subscribe((res: any) => {
console.debug('prediction id', id);
console.debug('res', res);
}, err => {
this.handleError(err);
});
return seq;
}
这不起作用,因为Property 'id' does not exist on type 'ArrayBuffer'.
使用
filter(prediction => prediction.id === id)
代替。我知道我无法直接获取存储在ArrayBuffer中的数据。但我想,在处理Observable时,已经存在这种交互的实现,特别是在尝试根据其属性过滤响应数据时。 或者我是否必须为此创建自己的实现?考虑到可以直接在简单的单行评估上过滤元素,这听起来是错误的。但我可能会在这里误读一些东西。
响应机构如下。每个预测都是一个对象。
[
{
"categories": [
0,
1
],
"id": 1,
"name": "Foo"
},
...
]
更新
做了一些进一步的研究和反复试验,但我仍然无法过滤这些元素。 ArrayBuffer
类型阻止我访问元素,这意味着我无法过滤它们。
我尝试将结果硬编码为提供程序中的可解析JSON,然后通过过滤器运算符访问Observable:
var predictions = from([
{categories:[0,1], id:1},
{categories:[0,1], id:2},
{categories:[0,2], id:3},
{categories:[0,1], id:4},
{categories:[0,1], id:5},
{categories:[0,4], id:6},
{categories:[0,1], id:7},
{categories:[0,1], id:8},
{categories:[0,1], id:9},
{categories:[0,1], id:10},
{categories:[0,1], id:11}
]);
var seq = predictions.pipe(
filter(prediction => {
//print every single prediction
console.debug('prediction', prediction);
return prediction;
})
);
这按预期工作,每个对象都被读取并视为单个实体,这就是我想要的。
但是,如果我执行GET请求,则响应存储在ArrayBuffer
类型中,这会使行为完全不同:
var predictions = this.http.get('http://localhost/myApi/predictions');
var seq = predictions.pipe(
filter(function(prediction, i){
//the whole array is printed
console.debug('prediction', prediction);
console.info('i', i);
return true;
})
);
因此,只能读取/打印整个数组,而不是只能读取的每个元素。这是有道理的,因为它是一个ArrayBuffer,因此是一个字节流,据我所知。但这使得无法读取该数组中的每个元素(即每个预测对象)并对其应用过滤器。
如何将RxJS'filter()或map()方法应用于此ArrayBuffer的内容?或者我如何转换这个ArrayBuffer才能这样做?
我尝试找到解决方案的次数越多,我就越觉得在向应用程序发送JSON响应之前我已经过滤服务器端。但对于很多用例而言,这似乎效率低下。我无法想象不存在这种情况的实施。
我错过了什么?
答案 0 :(得分:1)
这里有很多事情发生,所以我会尽力将其分解。
RxJS Lettable Operators(可能无法找到您的运营商的原因)
Property '(flatMap|filter)' does not exist on type 'Observable<ArrayBuffer>
- 这可能是您当前版本的RxJS的问题。在最近的版本中,他们删除了这些可链接的方法,以采用更实用的方法。相反,有一个pipe
方法,它将一系列函数应用于事件流。这样你只需要导入你正在使用的东西 - 而不是整个RxJS库。点击此处:https://hackernoon.com/rxjs-reduce-bundle-size-using-lettable-operators-418307295e85
新API样式的示例:
this.api.get(this.epPredictions, {prediction_id: id})
.pipe(filter(prediction.id === id), share())
share()
做什么?
share()
仅在您拥有多个订阅者时才有用 - 您不应该在此处使用它。默认情况下,当订阅observable时,它将获得自己的事件。这意味着如果您的observable订阅次数太多,那么您的observable可能会被执行两次,每个订阅者都会获得自己的事件。 share()
将向两个订阅者发送相同的事件并执行一次您的observable。在RxJS中,这意味着share()
将产生一个&#34;可观察序列,其中包含通过组播源序列产生的序列的元素。&#34; https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/share.md
阵列缓冲区
引用Mozilla - &#34; ArrayBuffer是一种数据类型,用于表示通用的固定长度二进制数据缓冲区。你不能直接操作ArrayBuffer的内容;相反,您创建一个类型化的数组视图或一个表示特定格式的缓冲区的DataView,并使用它来读取和写入缓冲区的内容。&#34; https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays
换句话说,ArrayBuffer不是标准的JS数组 - 它是某种数据(如图像)的原始表示。需要更多关于其内容的信息才能正确回答您的问题。