【问题标题】:Avoid null returned from background async request避免从后台异步请求返回 null
【发布时间】:2018-09-29 00:35:04
【问题描述】:

我有一个非常大的请求,需要 15 秒才能返回数据。我想在用户登录时调用该请求,以减少他们前往加载该数据的路线所需的时间(他们可以在完成后到达那里,这将立即向他们显示数据,或者可能尚未完成,但此时只让他们等待几秒钟)。

因此,当用户登录并成功时,我会请求大型数据集:

this.getDataService.getAsyncData(data.LinkToken); // This loads request from data service

然后,当数据返回时,我将该数据保存到本地存储中,然后当用户登陆从 ngOnOnit() 发出该请求的路线上时,可以检索该数据

getAsyncData(linkToken){ //this is background request that is loading while user navigates through app
   this.httpC.get(this.baseUrl + "/AccountInfo/Data?linkToken=" + linkToken + "&deliveryTypeId=" + 0 + "&pickupLocationId=" + 0 + "&paymentTypeId=" + 0).map((res:Response) => res.json()).subscribe(res => {
       this.asycCollection = res;
       this.globalService.setData(this.asycCollection) //This passes this data to service that stores in local storage
       console.log(this.asycCollection);
    })
}

然后,该数据可以作为承诺请求从该路由加载时加载的组件返回

//This sets local storage with the data
setData(refillObject:any){ 
    this.refillObj = refillObject;
    window.localStorage.setItem("refillData", JSON.stringify(this.refillObj))
}
//This gets promise of that background async call
getData(){
    let refillInformation:any = window.localStorage.getItem("refillData");

    return new Promise<any>((resolve, reject) => resolve(refillInformation));
}

然后,我想从我的路由组件中检索此数据,但仅在它完成加载数据后才能检索,否则它会返回 null,当然没有任何效果。所以,如果用户快速导航到这个页面,那么它会返回 null(因为请求还没有完成加载数据)并爆炸,但如果用户在请求完成后返回,一切都会按设计进行。

加载完成后如何等待并获取数据?请记住,这是用户登录时的后台异步请求,我正在从本地存储中检索,而不是向 REST Svc 发出新请求。

组件代码:

getAsyncRefills(success){
    this.globalService.getData().then(data => { //everything below this blows up if the page is loaded before the data request has finished loading to local storage.
        this.orderData = JSON.parse(data);
this.currentDeliveryType = this.orderData.DeliveryTypes.find((item) => 
item.DeliveryTypeId == this.orderData.DeliveryTypeId);
        this.currentPaymentArr = this.currentDeliveryType.PaymentTypes;
        this.currentPickupLocations = this.currentDeliveryType.PickupLocations;


        this.setOptions();
        this.buildOrders();

    })

}

【问题讨论】:

  • 您使用 localStorage 有什么原因吗?还有为什么你在一个应用程序中使用 Observables 和 Promises?我假设缓慢的异步请求 - 后来需要来自 LocalStorage 的数据的代码是同一个应用程序正确吗?
  • 我尝试单独使用 observable 或 promise,但它仍在加载 null 值,所以我在之前添加了本地存储只是为了确保我最终可以获得对象,但这绝不是一个完成的想法。v它们确实都在同一个应用程序中。我目前正在研究使用 EventEmitter 来订阅服务中的事件,该事件在返回时会发出检索到的数据,也有点磕磕绊绊(订阅发出的值而不是在数据返回时调用函数)。如果您有任何建议,我很乐意接受。

标签: javascript angular typescript promise


【解决方案1】:

我会通过以下方式解决这个问题。

我会建立一个服务,负责

  • 在后端触发繁重查询的执行
  • 作为公共属性公开一个 Observable,当查询结果到达时发出
    • 一旦数据从后端到达,它就会使用公开为公共属性的 Observable 发出数据

这个服务通过依赖注入注入到执行登录的组件和需要显示数据的组件中。

进行登录的组件,一旦登录成功,就会调用触发查询的服务方法。

需要显示数据的组件可以使用服务公开为公共属性的Observable在数据到达后显示数据。有几种方法可以做到这一点。您可以使用来自 Angular 的 async 管道,它允许您直接在模板中引用 Observable,或者您可以订阅 Observable 然后使用订阅逻辑中定义的函数来填充所需的变量。

【讨论】:

    【解决方案2】:

    对于这样的事情,我不会使用本地存储,但会使用服务(抱歉没有 IDE,所以代码可能不完美)。

    @Injectable()
    export class ExpensiveDataStore {
    
      private expensiveData_: ConnectableObservable<ExpensiveThing>;
      private connection: Subscription;
    
      get expensiveData(): Observable<ExpensiveThing> {
        if(!this.expensiveData_) {
          throw Error('Must initialize store first!');
        }
        return this.expensiveData_;
      }
    
      initialize() {
        this.expensiveData_ = this.goFetchExpensiveData().publishLast();
        this.connection = this.expensiveData.connect();
      }
    
      void reset() {
        this.connection.unsubscribe();
        this.connection = this.expensiveData.connect();
      }
    
    }
    

    在您的app.component.ts 或一些高级组件中,您可以调用initialize()。在您需要数据的组件中,您可以订阅expensiveData

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-03-14
      • 1970-01-01
      • 1970-01-01
      • 2015-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多