简体   繁体   English

如何在Angular中处理异步函数

[英]How to handle async functions in Angular

 //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 

I keep running up against use cases where I'm needing to deal with asynchronous data while building an Angular application. 我一直在遇到需要在构建Angular应用程序时处理异步数据的用例。 I've employed a number of strategies to deal with things (async pipe, ngIf waiting for certain variables to be ready etc.) but I feel like I'm missing something. 我已经采用了许多策略来处理事情(异步管道,ngIf等待某些变量准备就绪等)但我觉得我错过了一些东西。 Here are the specifics of the latest challenge... I have an array that is being populated from Firebase. 以下是最新挑战的具体内容......我有一个从Firebase填充的阵列。 This is being done via a function call upon load of the application. 这是在加载应用程序时通过函数调用完成的。 Let's call the array 'sourceArray' 我们调用数组'sourceArray'

I then want to do some 'work' on that array to seed content elements in other components. 然后,我想在该数组上做一些“工作”,以便在其他组件中播放内容元素。 For example doing a 'filter' on that array and creating a new array from those results. 例如,对该阵列执行“过滤器”并根据这些结果创建新数组。

The challenge I keep running into (this is just the latest example) is that when I call the function that does 'other work' on the sourceArray I get errors back saying blah blah is undefined because it hasn't been fully populated from firebase yet. 我一直在遇到的挑战(这只是最新的例子)是当我调用在sourceArray上执行'其他工作'的函数时,我得到错误,说blah blah是未定义的,因为它还没有完全填充来自firebase 。 So to break this down simply... -Source variable being populated from something that takes some 'time' -Want to do work on that source variable only 'after' it's been fully populated 所以要简单地解决这个问题...... - 源变量是从需要一些'时间'的东西填充的 - 只有'在'完全填充之后才能对该源变量进行处理

I've read up on using lifecycle hooks (Ie putting the dependent function in a hook that runs after the source function) etc. and have limited success using that strategy. 我已经阅读了使用生命周期钩子(即将依赖函数放在源函数之后运行的钩子中)等等,并且使用该策略的成功有限。 Also of note I'm 'subscribing' to the firebase data in the source array. 另外值得注意的是,我正在订阅源阵列中的firebase数据。

I've also investigated potentially using async and await but don't really understand how I would apply that to this use case. 我还调查过可能使用async和await但是我真的不明白我将如何应用于这个用例。 Any advice would be appreciated and happy to provide more details if this is not sufficient. 如果这还不够,任何建议都会很感激,并乐意提供更多细节。

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

First, you are not using the filter() method as intended. 首先,您没有按预期使用filter()方法。 You are using it like how you'd use map() . 你正在使用它就像你使用map() You could just do 你可以做到

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

For your main concern, you could setup a watcher in your service that filters out the original array when it's populated. 对于您主要关心的问题,您可以在服务中设置一个观察程序,在填充原始数组时过滤掉它。

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

And then, 接着,

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM