1

I have a for each loop where I check something inside of it. This check is asynchronous and when this check is false, I want to break the loop. Here is my code:

addReservation(reservation: Reservation) {
    this.deskService.loadDesksWhereRangeGreater(reservation.persons).subscribe(
        desks => {
            if (desks.length > 0) {

                for (const desk1 of desks) {
                    console.log('checking');
                    if (this.checkForAvailability(desk1, reservation)) {
                        console.log('found');
                    }
                }
            }
        }
    );
}

async checkForAvailability(desk: Desk, reservation: Reservation) {

    await this.db.collection('Desks').doc(desk.id)
    .collection('Reservations', ref => ref.where('timestamp', '<=', reservation.timestamp + this.reservationDelta)
    .where('timestamp', '>', reservation.timestamp - this.reservationDelta))
    .valueChanges().subscribe(reservations => {
        if (reservations.length === 0) {
            console.log('reservation possible for ' + desk.nr);
            return true;
        } else {
            console.log(desk.nr + ' Belegt');
            return false;
        }
    });
}

However the await part isn't really working. It just iterates through the loop without waiting for the asynchronous function each iteration.

colxi
  • 7,640
  • 2
  • 45
  • 43
Jonas
  • 7,089
  • 15
  • 49
  • 110
  • You need to return the promise from checkForAvailability and async await in addReservation – Aldo Sanchez Aug 01 '18 at 21:02
  • Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Igor Aug 01 '18 at 21:11
  • 1
    Also you can't use `async/await` with an observable, it must be used with a Promise. – Igor Aug 01 '18 at 21:12

2 Answers2

1

You need to await the result from checkForAvailability:

addReservation(reservation: Reservation) {
    this.deskService.loadDesksWhereRangeGreater(reservation.persons).subscribe(
        async desks => {
            if (desks.length > 0) {
                for (const desk of desks) {
                    const available = await this.checkForAvailability(desk, reservation)
                    if (!available) { break }
                }
            }
        }
    );
}

checkForAvailability(desk: Desk, reservation: Reservation) {
  // here, you need to return a promise
  return new Promise(resolve => {
    this.db.collection('Desks').doc(desk.id)
    .collection('Reservations', ref => ref.where('timestamp', '<=', reservation.timestamp + this.reservationDelta)
    .where('timestamp', '>', reservation.timestamp - this.reservationDelta))
    .valueChanges().subscribe(reservations => {
      resolve(reservations.length === 0)
    });
  })
}
eosterberg
  • 1,422
  • 11
  • 11
  • Thanks I got the Idea but when I do `const available = await this.checkForAvailability(desk, reservation);` I get a syntax error " 'await' expression is only allowed within an async function". I have declared the addReservation function as async. – Jonas Aug 02 '18 at 08:58
  • Ok, you have to declare the inner callback as async, updated my answer. – eosterberg Aug 02 '18 at 09:05
1

You need to return a Promise in the checkForAvailability function, and addReservation function must be async in order to use await.

The await operator is used to wait for a Promise. It can only be used inside an async function.

Here , an exemple of how to implement an async loop :

async function asyncLoop(){
  console.log('loop 10 times')
  for(let i=0; i<10; i++) await doSomethingAsync(i);
  console.log('loop done!')
}

function doSomethingAsync(i){
  return new Promise( function(resolve,reject){
    // do your async stuff ... and then resolve()
    //
    // in this example i will use a timeout to simulate
    // an async operation.
    setTimeout( function(){
      console.log(i,'done!');
      resolve();
    }, 1000);
  })
}

asyncLoop()
colxi
  • 7,640
  • 2
  • 45
  • 43