如何在Angular中处理异步函数

时间:2019-04-21 18:39:44

标签: javascript angular asynchronous async-await observable

//This is a function that is in my data service (in Angular) that basically gets data and puts it in an array
getTenantData() {
  //This is the function that is called by app.component.ts
  //It's job is to get data from the tenants collection and map it to an array called tenants
  this.afs //afs is simply what i named the Firebase db in my constructor
    .collection('tenants')
    .snapshotChanges()
    .subscribe(values => {
      this.tenants = values.map(value => {
        return {
          id: value.payload.doc.id,
          ...value.payload.doc.data()
        };
      });
    });
}


//Then if I create a function that performs some 'work' on the tenants array in another component like so
filterMyArray() {
  this.ad.tenants.filter(values => { //ad is simply what i called the dataservice in the constructor
    if (values.id == 'Some Value') {
      this.filteredArray.push(values);
    }
  });
  console.log(this.filteredArray);
}

//This works fine if I call it using some manual 'after load' approach (like clicking a button)
//Doesn't work if I call it in ngOnInit for instance as tenants hasn't been populated yet
//Throws typeerror cannot read property filter of undefined etc.
//So challenge is how do I get the second function to wait for the first
//Keep in mind first function is in a service not in the same component as second function

我一直在面对在构建Angular应用程序时需要处理异步数据的用例。我采用了许多策略来处理事情(异步管道,ngIf等待某些变量准备就绪等),但我感觉好像缺少了一些东西。以下是最新挑战的细节... 我有一个从Firebase填充的数组。这是通过在应用程序加载时通过函数调用来完成的。让我们将数组称为“ sourceArray”

然后,我想对该数组做一些“工作”,以将内容元素植入其他组件中。例如,对该数组执行“过滤”并根据这些结果创建一个新数组。

我一直遇到的挑战(这只是最新的示例)是,当我在sourceArray上调用执行“其他工作”的函数时,我收到错误消息,说是这样的,因为它没有被完全填充从firebase还没有。所以简单地分解一下... -从需要一些“时间”的内容填充源变量 -仅在完全填充后才想在该源变量上工作

我已经阅读了使用生命周期钩子(即将依赖函数放在源函数之后运行的钩子中)等知识,并且使用该策略的成功有限。还要注意的是,我正在“订阅”源数组中的firebase数据。

我也已经潜在地使用async和await进行了调查,但是我不太了解如何将其应用于此用例。如果不够的话,我们将不胜感激,并乐意提供更多详细信息。

2 个答案:

答案 0 :(得分:0)

// This is how you can await a call from firebase 
// & later do something after call is completed

// write
async function writeData (userId, name, email, imageUrl) {
 await firebase.database().ref('users/' + userId).set({
    username: name,
    email: email,
    profile_picture : imageUrl
  });
  // do something when after is executed
}

// read
async function readData (userId) {
 let response = await firebase.database().ref('/users/' + userId).once('value')
 console.log(response.val())
 // do something after above is executed 
}

答案 1 :(得分:0)

首先,您没有按预期使用filter()方法。就像使用map()一样使用它。你可以做

filterMyArray() {
 this.filteredArray = this.ad.tenants.filter(values => values.id == 'Some Value');
  console.log(this.filteredArray);
}

出于主要考虑,您可以在服务中设置一个观察程序,以在填充原始数组时过滤掉原始数组。

constructor() {
  this.setupWatcher();
}

setupWatcher() {
  interval(1000).pipe(
        switchMap(() => of(this.ad.tenants)),
        filter(response => response && response.length > 0),
        take(1))
        .subscribe((input: Tenants[]) => {
          //do stuff
          this.filterMyArray(input);
        });
}

然后

filterMyArray(originalArray: Tenants[]) {
  this.filteredArray = originalArray.filter(values => values.id == 'Some Value');
  console.log(this.filteredArray);
}