我有一个服务,它可以返回一个观察者,对我的服务器进行http请求并获取数据。我想使用这些数据,但我总是得到一个叫 "Observablehttpasync "的响应。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()
当你实际发出("fire")你的http请求后,用 subscribe
您将 等待 的响应。在等待的过程中,javascript会执行下面这段代码,如果遇到同步的assignmentsoperations会立即执行。
所以在订阅了 getEventList()
并等待回复。
console.log(this.myEvents);
行将被立即执行。它的值是 undefined
在服务器的响应到达之前(或者说你首先初始化它的任何东西)。
这类似于做。
ngOnInit(){
setTimeout(()=>{
this.myEvents = response;
}, 5000);
console.log(this.myEvents); //This prints undefined!
}
那么我们如何克服这个问题呢?我们将使用回调函数,它就是
subscribe
方法。因为当数据从服务器上到达时,它将会在subscribe
与响应。
所以把代码改成:
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents); //<-- not undefined anymore
});
会在一段时间后打印出响应。
除了记录响应之外,可能还有很多事情要做;你应该在回调中完成所有这些操作(在回调中的 subscribe
函数),当数据到达时。
还有一点值得一提的是,如果你来自于一个 Promise
背景、 then
回调对应于 subscribe
有观察到的东西。
你不应该尝试把一个异步操作改成同步操作(不是说你可以)。我们使用异步操作的原因之一是为了不让用户在等待一个操作完成的同时,可以在这段时间内做其他事情。假设你的一个异步操作需要3分钟才能完成,如果我们没有异步操作,界面会冻结3分钟。
建议阅读。
本答案的原创功臣是:。如何返回异步调用的响应?
但随着angular2的发布,我们接触到了typecript和observables,所以这个答案希望能涵盖用observables处理异步请求的基础知识。
angularjavascript中的http调用是异步操作,所以当你进行http调用时,它会分配新的线程来完成这个调用,然后用另一个线程开始执行下一行,这就是为什么你得到的是未定义的值,所以做以下修改来解决这个问题。
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents); //<-this become synchronous now
});
您可以使用 asyncPype 如果你只在模板中使用myEvents。
这里是使用asyncPype和Angular4 HttpClient的例子。https:/stackblitz.comeditangular-rhioqt?file=app%2Fevent.service.ts。
Observables是懒惰的,所以你必须订阅才能得到值。你在代码中正确地订阅了它,但同时在'订阅'块之外记录了输出。这就是为什么它是 "未定义 "的原因。
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
得到初始化。
请把你的console.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));
}
另外,请确保你的响应映射到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;})
}
未定义,因为这里的值是在服务的任何数据被设置之前从上面的订阅服务调用中记录下来的。 所以你必须等到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方法里面做一个Console日志,当数据在myEvents变量中设置时,会做日志。
ngOnInit(){
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
// This prints the value from the response
console.log(this.myEvents)
});
}
你可以简单地尝试这个方法--
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');
}