【问题标题】:How to synchronise Angular2 http get?如何同步Angular2 http get?
【发布时间】:2016-01-22 13:39:24
【问题描述】:

我知道使用 observable 我可以在请求完成时执行一个方法,但是我如何才能等到 http get 完成并使用 ng2 http 返回响应?

getAllUser(): Array<UserDTO> {
    this.value = new Array<UserDTO>();
    this.http.get("MY_URL")
                    .map(res => res.json())
                    .subscribe(
                        data => this.value = data,
                        err => console.log(err),
                        () => console.log("Completed")
    );

    return this.value;
} 

“值”在返回时将为空,因为 get 是异步的..

【问题讨论】:

  • 你可以使用$q服务或者在ajax成功回调中执行你的函数
  • @Vineet Angular 2 不使用$q

标签: javascript angular typescript angular2-http


【解决方案1】:

您的服务类:/project/app/services/sampleservice.ts

    @Injectable()
    export class SampleService {

      constructor(private http: Http) {
      }

      private createAuthorizationHeader() {
         return new Headers({'Authorization': 'Basic ZXBossffDFC++=='});
      }


      getAll(): Observable<any[]> {
        const url='';
        const active = 'status/active';
        const header = { headers: this.createAuthorizationHeader() };
        return this.http.get(url + active, header)
          .map(
            res => {
              return res.json();
            });
      }

    }

您的组件:/project/app/components/samplecomponent.ts

export class SampleComponent implements OnInit  {


  constructor(private sampleservice: SampleService) {
  }

  ngOnInit() {
   this.dataset();
  }

  dataset(){
    this.sampleservice.getAll().subscribe(
      (res) => {
        // map Your response with model class
        // do Stuff Here or create method 
        this.create(res);
      },
      (err) => { }
    );
  }
  create(data){
   // do Your Stuff Here
  }

}

【讨论】:

  • 当响应发生变化时,observable 会自动调用您的方法并使用新元素进行更新。
【解决方案2】:

通过查看角度源 (https://github.com/angular/angular/blob/master/packages/http/src/backends/xhr_backend.ts#L46),很明显 XMLHttpRequest 的 async 属性没有被使用。 XMLHttpRequest的第三个参数需要设置为“false”,用​​于同步请求。

【讨论】:

  • 大多数浏览器不再支持同步请求。为了获得更好的 UI 体验...
【解决方案3】:

请找到您的问题的代码 下面是组件和服务文件。并且代码在同步时工作正常

import { Component, OnInit } from '@angular/core';
import { LoginserviceService } from '../loginservice.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
  model:any={};
  constructor(private service : LoginserviceService) { 
}

ngOnInit() {

}
save() {
   this.service.callService(this.model.userName,this.model.passWord).
   subscribe(
      success => {
        if(success) {
            console.log("login Successfully done----------------------------    -");
            this.model.success = "Login Successfully done";
     }},
    error => console.log("login did not work!")
  );
 }

}

下面是服务文件..

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { UserData } from './UserData';
import 'rxjs/add/operator/map'
import 'rxjs/add/operator/toPromise'
import {Observable} from 'rxjs/Rx'

@Injectable()
   export class LoginserviceService {
   userData = new UserData('','');   
   constructor(private http:Http) { }

    callService(username:string,passwrod:string):Observable<boolean> {
     var flag : boolean;      
     return (this.http.get('http://localhost:4200/data.json').
       map(response => response.json())).
        map(data => {
          this.userData = data;
          return this.loginAuthentication(username,passwrod);
        });
      }

  loginAuthentication(username:string,passwrod:string):boolean{
     if(username==this.userData.username && passwrod==this.userData.password){
        console.log("Authentication successfully")
        return true;
   }else{
     return false;
   }


  }
}

【讨论】:

    【解决方案4】:

    另一种解决方案是实现排序的优先级队列。

    据我了解,在添加订阅者之前,http 请求不会被执行。因此,您可以这样做:

    Observable<Response> observable = http.get("/api/path", new RequestOptions({}));
    
    requestPriorityQueue.add(HttpPriorityQueue.PRIORITY_HIGHEST, observable,
                     successResponse => { /* Handle code */ }, 
                     errorResponse => { /* Handle error */ });
    

    这假定requestPriorityQueue 是注入到您的组件中的服务。优先级队列将条目存储在一个数组中,格式如下:

    Array<{
        observable: Observable<Response>, 
        successCallback: Function, 
        errorCallback: Function
    }>
    

    您必须决定如何将元素添加到您的数组中。最后,后台会发生以下情况:

    // HttpPriorityQueue#processQueue() called at a set interval to automatically process queue entries
    

    processQueue 方法会做这样的事情:

    protected processQueue() {
        if (this.queueIsBusy()) {
            return;
        }
    
        let entry: {} = getNextEntry();
        let observable: Observable<Response> = entry.observable;
    
        this.setQueueToBusy(); // Sets queue to busy and triggers an internal request timeout counter.
        observable.subscribe()
            .map(response => {
                this.setQueueToReady();
                entry.successCallback(response);
            })
            .catch(error => {
                this.setQueueToReady();
                entry.errorCallback(error);
            });
    }
    

    如果您能够添加新的依赖项,您可以尝试使用以下 NPM 包:async-priority-queue

    【讨论】:

      【解决方案5】:

      我看了看,但找不到任何方法可以使 HTTP 调用同步而不是异步。

      因此,解决此问题的唯一方法是:将您的调用包装在带有标志的 while 循环中。在该标志具有“继续”值之前,不要让代码继续运行。

      伪代码如下:

      let letsContinue = false;
      
      //Call your Async Function
      this.myAsyncFunc().subscribe(data => {
         letsContinue = true;
      }; 
      
      while (!letsContinue) {
         console.log('... log flooding.. while we wait..a setimeout might be better');
      }
      

      【讨论】:

        【解决方案6】:

        如您所见,第一个回调等待来自请求的数据,然后 在那里你可以继续你的逻辑(或使用第三个)

        示例:

        .. subscribe( data => { 
                      this.value = data; 
                      doSomeOperation;
                      }, 
                      error => console.log(error), 
                      () => {console.log("Completed");
                              or do operations here..;
                            }
        });
        

        【讨论】:

        • 你能在“在这里做操作...”的地方输入另一个订阅请求吗?
        【解决方案7】:

        如何使用 $.ajax(of jQuery) 或 XMLHttpRequest。

        它可以用作异步。

        【讨论】:

        • jQuery 不应该与 Angular 一起使用
        • 我不这么认为。
        • 你为什么这么认为?一些程序员在 Angular 中偏好使用 jQuery。
        • Angular 2 中已经有 Http 和 4.3 中的 HttpClient 来执行异步 http 请求。另外,请阅读此处了解为什么将 jQuery 与 Angular 一起使用是不好的:stackoverflow.com/questions/41834089/…
        【解决方案8】:

        您不应该尝试使 http 调用同步运行。从来不是一个好主意。

        在您的 getAllUser 实现中,它应该从函数返回一个可观察对象,并且调用代码应该订阅,而不是您在方法本身内创建订阅。

        类似

        getAllUser(): Observable<UserDTO> {
                return this.http.get("MY_URL")
                                .map(res => res.json());
        } 
        

        在你调用代码时,你应该订阅并做任何你想做的事情。

        【讨论】:

        • 此回复提供了问题的替代实现,我很感激回复。但是,这并不能回答问题。有没有办法发出同步http请求?我正在寻找同一个问题的答案,并且我可以阻止浏览器(实际上我想要它),直到我得到响应。
        • 这个答案只建议不要使用sync xhr,它从不解释问题用例中的原因,甚至以任何方式回答问题,而只提供另一个问题的答案。
        • 通过查看角度源,XMLHttpRequest 的 async 属性似乎没有被使用。
        • @inki 在浏览器中发出“同步”请求会冻结整个浏览器。这是一种糟糕的用户体验。
        • @inki 请参阅 2012 年 1 月的 Google 帖子关于不再允许同步 XHR developers.google.com/web/updates/2012/01/…
        猜你喜欢
        • 2017-10-23
        • 1970-01-01
        • 2017-06-23
        • 1970-01-01
        • 1970-01-01
        • 2016-05-13
        • 2018-02-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多