Javascript 如何在angular中从可观察的/http/async调用返回响应?

Javascript 如何在angular中从可观察的/http/async调用返回响应?,javascript,angular,asynchronous,typescript,observable,Javascript,Angular,Asynchronous,Typescript,Observable,我有一个服务,它返回一个observable,向我的服务器发出http请求并获取数据。我想使用这些数据,但最终总是得到未定义的。有什么问题吗 服务: @Injectable() export class EventService { constructor(private http: Http) { } getEventList(): Observable<any>{ let headers = new Headers({ 'Content-Type': 'app

我有一个服务,它返回一个observable,向我的服务器发出http请求并获取数据。我想使用这些数据,但最终总是得到未定义的
。有什么问题吗

服务

@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!
  }
}
它未定义的原因是您正在进行异步操作。这意味着完成
getEventList
方法需要一些时间(主要取决于您的网络速度)

让我们看看http调用

this.es.getEventList()
使用
subscribe
实际发出(“激发”)http请求后,您将等待响应。在等待时,javascript将执行此代码下面的行,如果遇到同步分配/操作,它将立即执行这些行

因此,在订阅
getEventList()
并等待响应之后

console.log(this.myEvents)

该行将立即执行。在响应从服务器(或您首先初始化它的对象)到达之前,它的值是
未定义的

这类似于:

ngOnInit(){
    setTimeout(()=>{
        this.myEvents = response;
    }, 5000);

    console.log(this.myEvents); //This prints undefined!
}

解决方案:

@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!
  }
}
那么我们如何克服这个问题呢?我们将使用回调函数,它是
subscribe
方法。因为当数据从服务器到达时,它将在带有响应的
subscribe

因此,将代码更改为:

this.es.getEventList()
    .subscribe((response)=>{
        this.myEvents = response;
        console.log(this.myEvents); //<-- not undefined anymore
    });
this.es.getEventList()
.订阅((响应)=>{
this.myEvents=响应;

console.log(this.myEvents);//还要确保将响应映射到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;})
}
getEventList():可观察{
let headers=新的头({'Content-Type':'application/json'});
let options=newrequestoptions({headers:headers});
返回此.http.get(“http://localhost:9999/events/get“,选项)

.map((res)=>{return res.json();})在angular/javascript中进行http调用是异步操作。 所以,当您进行http调用时,它将分配新线程来完成此调用,并在下一行使用另一个线程开始执行。 这就是为什么会得到未定义的值。 因此,请进行以下更改以解决此问题

this.es.getEventList()  
      .subscribe((response)=>{  
       this.myEvents = response;  
        console.log(this.myEvents); //<-this become synchronous now  
    });
this.es.getEventList()
.subscribe((响应)=>{
this.myEvents=响应;

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');
    }
如果仅在模板中使用myEvents,则可以使用


在这里,asyncPipe和Angular4 HttpClient的示例是惰性的,因此您必须订阅以获取值。您在代码中正确订阅了它,但同时将输出记录在“订阅”块之外。这就是为什么它是“未定义”的原因

ngOnInit() {
  this.es.getEventList()
    .subscribe((response) => {
        this.myEvents = response;
    });

  console.log(this.myEvents); //Outside the subscribe block 'Undefined'
}
因此,如果您将其记录在subscribe块中,那么它将正确地记录响应

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);
        });
  }

由于角度进程异步,因此结果未定义。 您可以按以下方式进行尝试:

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)
  }

您可以使用以下方法从服务返回值

服务内容如下:

 export class AppServiceService {
    
      constructor(private http: HttpClient) { }
    
      getStudentDetails(): Observable<Student[]>{
        let headers = new Headers({ 'Content-Type': 'application/json' });
        let options = new RequestOptions({ headers: headers });
        return this.http.get<Student[]>('http://localhost:8080/api/student',options);
    
      }
    
    }
有关更多参考,请参阅以下url:


这是一个很好的观点,需要强调一个事实,即不可能将非同步操作转换为同步操作。@n00dl3谢谢你的提示!我已经在“你不应该做什么”中解释过了:部分。请随意编辑。这是否回答了您的问题?@HereticMonkey该帖子已记入answer@HereticMonkey是的,是的,因为它是特定于框架的,是可观察的。当我复制angular/rxjs,异步问题的答案时,人们感到困惑,说
,然后
观察不起作用;这对于有角度的回答者来说,这是显而易见的,但对你来说显然不是。而且我认为答案中的分数足够了,但我也会改变问题。而且(!)通过此实现,用户无需取消订阅:@SanJayFalcon因为这是一个http请求,所以无需取消订阅。当发问者在发帖的同一时间回答问题时。这是一个停下来写博客帖子的好地方instead@JonasPraem没错,但沙尔没有错我的问题有点类似。但这个答案也解决了这个问题。:-)
export class AppComponent {
  
  title = 'angular-demo';

  constructor(private appService: AppServiceService) { }

   studentDetails: Student[];

  ngOnInit(): void {
    this.appService.getStudentDetails().subscribe(data => {
      this.studentDetails=data;
    },error=>{
         console.log(error);
    });

  }
}