为什么我的提供者加载数据两次?

时间:2017-05-13 21:51:07

标签: angular ionic-framework promise angular-services

我目前正在关注一个在屏幕上显示国家公园的Ionic应用程序的教程。数据存储在本地文件中,由我的Provider加载,但Provider加载数据两次。我想在app.component.ts启动时加载数据,然后当页面加载(park-list.ts)时,它应该只获取已经加载的数据,但是提供程序加载数据两次,即使我得到了一个if我的load()方法中的条件。 (它记录“下载”两次)

提供者:park-data.ts

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';

@Injectable()
export class ParkData {

  data: any = null;

  constructor(public http: Http) {
    console.log('Hello ParkData Provider');
  }

  load() {
    if (this.data) {
      return Promise.resolve(this.data);
    }
    return new Promise((resolve) => {
      this.http.get("assets/data/data.json")
        .map(res => res.json())
        .subscribe(data => {
          console.log("DOWNLOADING");
          this.data = data;
          resolve(this.data);
        })
    });
  }

  getParkData() {
    return this.load().then((data) => { return data });
  }

}

app.component.ts

import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';

import { TabsPage } from '../pages/tabs/tabs';
import { ParkData } from "../providers/park-data";


@Component({
  templateUrl: 'app.html',
  providers: [ParkData]
})
export class MyApp {
  rootPage = TabsPage;

  constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen, public parkData: ParkData) {
    console.log(parkData);
   platform.ready().then(() => {
      // Okay, so the platform is ready and our plugins are available.
      // Here you can do any higher level native things you might need.
      statusBar.styleDefault();
      splashScreen.hide();
    });
    this.parkData.load();

  }

公园list.ts

import { Component } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';

import { ParkData } from "../../providers/park-data";
import { ParkDetails } from "../park-details/park-details";

@Component({
  selector: 'page-park-list',
  templateUrl: 'park-list.html'
})
export class ParkListPage {

  parks: Array<Object> = [];

  constructor(public navCtrl: NavController, public navParams: NavParams, public parkData: ParkData) {
      this.parkData.getParkData().then(data => this.parks = data);
  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad ParkListPage');
  }

  openParkDetails(park): void {
    this.navCtrl.push(ParkDetails, {parkData: park});
  }

}

当我将this.parkData.getParkData().then(data => this.parks = data);放入setTimout函数时,我的提供商只会“下载”一次数据。是因为parkData.load()parkData.getParkData()被一个接一个地调用得如此之快,以至于我的提供商中的data属性保持null? 我希望你能帮我解决这个问题。

1 个答案:

答案 0 :(得分:0)

你正在缓存数据而不是承诺 - 这是一个非常常见的错误。

您的代码容易受到竞争条件的影响,在这种情况下,可以接收两个数据请求(在接收数据之前) - 并触发两个不同的http请求。

    调用
  • load(),未设置this.data,创建承诺。
  • 再次调用
  • load(),未设置this.data,创建了承诺。
  • 第一个承诺结算,设置this.data
  • 第二个承诺结算,再次设置this.data

您可以通过缓存承诺而非数据来解决此问题:

export class ParkData {

  data: Promise<any> = null;

  constructor(public http: Http) {
    console.log('Hello ParkData Provider');
  }

  load() {
    if (this.data) {
      return this.data;
    }
    return this.data = this.http.get("/assets/data/data.json").toPromise();
  }


 getParkData() {
    return this.load().then((data) => { return data });
  }

}