提问人:eko 提问时间:3/28/2017 最后编辑:eko 更新时间:10/27/2022 访问量:48352
如何在 angular 中返回 Observable/http/async 调用的响应?
How do I return the response from an Observable/http/async call in angular?
问:
我有返回一个可观察对象的服务,该可观察对象向我的服务器发出 http 请求并获取数据。我想使用这些数据,但我最终总是得到.怎么了?undefined
服务:
@Injectable()
export class EventService {
constructor(private http: Http) { }
getEventList(): Observable<any>{
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.get("http://localhost:9999/events/get", options)
.map((res)=> res.json())
.catch((err)=> err)
}
}
元件:
@Component({...})
export class EventComponent {
myEvents: any;
constructor( private es: EventService ) { }
ngOnInit(){
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
});
console.log(this.myEvents); //This prints undefined!
}
}
我检查了如何返回异步调用的响应? 发布但找不到解决方案
答:
原因:
原因是您正在执行异步操作。这意味着完成该方法需要一些时间(主要取决于您的网络速度)。undefined
getEventList
因此,让我们看一下 http 调用。
this.es.getEventList()
在你实际发出(“触发”)你的 http 请求后,你将等待响应。在等待期间,javascript 将执行此代码下面的行,如果它遇到同步赋值/操作,它将立即执行它们。subscribe
所以在订阅并等待响应之后,getEventList()
console.log(this.myEvents);
行将立即执行。它的值是在响应从服务器到达之前(或者你首先初始化它的任何内容)。undefined
这类似于执行以下操作:
ngOnInit(){
setTimeout(()=>{
this.myEvents = response;
}, 5000);
console.log(this.myEvents); //This prints undefined!
}
**溶液:** >那么我们如何克服这个问题呢?我们将使用回调函数,即“订阅”方法。因为当数据从服务器到达时,它将在响应的“订阅”中。
因此,将代码更改为:
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents); //<-- not undefined anymore
});
将打印响应。.过了一段时间。
**你应该做什么:**
除了记录回复之外,可能还有很多事情要做;当数据到达时,您应该在回调(函数内部)执行所有这些操作。subscribe
另一件值得一提的事情是,如果你来自后台,回调对应于 observables。Promise
then
subscribe
**你不应该做什么:**
不应尝试将异步操作更改为同步操作(不是这样)。我们使用异步操作的原因之一是不要让用户等待操作完成,而他们可以在该时间段内执行其他操作。假设您的一个异步操作需要 3 分钟才能完成,如果我们没有异步操作,那么接口将冻结 3 分钟。
推荐阅读:
这个答案的原始功劳在于:如何从异步调用返回响应?
但是在 angular2 版本中,我们被引入了打字稿和可观察对象,所以这个答案希望涵盖了使用可观察对象处理异步请求的基础知识。
评论
此外,请确保将响应映射到 json 输出。否则,它将返回纯文本。你这样做是这样的:
getEventList(): Observable<any> {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.get("http://localhost:9999/events/get", options)
.map((res)=>{ return res.json();}) <!-- add call to json here
.catch((err)=>{return err;})
}
在 angular/javascript 中进行 http 调用是异步操作。 因此,当您进行 http 调用时,它将分配新线程来完成此调用,并使用另一个线程开始执行下一行。 这就是为什么你得到未定义的价值。 因此,请进行以下更改以解决此问题
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents); //<-this become synchronous now
});
您可以简单地尝试此方法-
let headers = new Headers({'Accept': 'application/json'});
let options = new RequestOptions({headers: headers});
return this.http
.get(this.yourSearchUrlHere, options) // the URL which you have defined
.map((res) => {
res.json(); // using return res.json() will throw error
}
.catch(err) => {
console.error('error');
}
如果仅在模板中使用 myEvents,则可以使用 asyncPipe。
这里的例子是 asyncPipe 和 Angular4 HttpClient 的例子
评论
Observables 是惰性的,因此您必须订阅才能获得值。您在代码中正确订阅了它,但同时将输出记录在“subscribe”块之外。这就是为什么它是“未定义”的。
ngOnInit() {
this.es.getEventList()
.subscribe((response) => {
this.myEvents = response;
});
console.log(this.myEvents); //Outside the subscribe block 'Undefined'
}
因此,如果您将其记录在订阅块中,那么它将正确记录响应。
ngOnInit(){
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents); //Inside the subscribe block 'http response'
});
}
这里的问题是,您正在初始化到哪个异步块中,而您只是在块外执行。
因此,在初始化之前被调用。this.myEvents
subscribe()
console.log()
subscribe()
console.log()
this.myEvents
请将您的控制台.log 代码也移动到 subscribe() 中,您就完成了。
ngOnInit(){
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents);
});
}
结果是未定义的,因为 angular process async . 您可以尝试如下操作:
async ngOnInit(){
const res = await this.es.getEventList();
console.log(JSON.stringify(res));
}
未定义,因为此处的值是在从上述订阅服务调用设置来自服务的任何数据之前记录的。因此,您必须等到ajax调用完成,然后从响应数据中设置数据。
getEventList(): Observable<any>{
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.get("http://localhost:9999/events/get", options)
.map((res)=> res.json())
.catch((err)=> err)
}
这里在 subscribe 方法中制作控制台日志,该方法将在 myEvents 变量中设置数据时制作日志。
ngOnInit(){
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
// This prints the value from the response
console.log(this.myEvents)
});
}
为此,您有 2 个选项:
假设我们有一个服务,它返回运输详细信息数组:
getShippingPrices(): Observable<IShippingDetails[]> {
return this.http.get<IShippingDetails[]>('/assets/shipping.json');
}
1.使用异步管道:当您只想在模板中显示结果时,简单的方法
在组件类中直接将 observable 赋值给变量:
export class ShippingComponent implements OnInit {
shipOptions1 = this.cartService.getShippingPrices();
constructor(private cartService: CartService) {}
ngOnInit() {}
}
然后在模板中使用异步管道:
<div *ngFor="let s of shipOptions1 |async">
<label>{{s.type}}</label>
</div>
参考:检查此 URL 中的第 4 点 https://angular.io/start/start-data#configuring-the-shippingcomponent-to-use-cartservice
2.使用订阅:当你想操作它或想在响应上/从响应中执行一些业务逻辑时
export class ShippingComponent implements OnInit {
shipOptions2: IShippingDetails[] = [];
constructor(private cartService: CartService) {}
ngOnInit() {
this.cartService.getShippingPrices().subscribe(response => {
this.shipOptions2 = response;
//console.log(this.myEvents);
//All other code using shipOptions2
});
}
}
评论
then
angular