Amaury Laroze
Amaury Laroze

Reputation: 217

Wait the end of a function before to start the next

I'm working on Ionic v4 with Angular.

In my project i use the BLE to communicate with a raspberry.

I have several step :

  1. Search Device around me
  2. Connect to this device
  3. Activate Notification
  4. Send Messages

Currently i have something like :

this.ble.scan().subscribe(result => {
  if (device === theDeviceIWant) {
    this.ble.connect(device.id).subscribe(result => {
      this.ble.startNotification(infosaboutDevice).subscribe(result => {
        // Message 1
        this.ble.writeWithoutResponse(infos, message).then(result => {
          // Message 2
          this.ble.writeWithoutResponse(infos, message).then(result => { 
            // Message 3
            this.ble.writeWithoutResponse(infos, message).then(result => {
              // Message X
              this.ble.writeWithoutResponse(infos, message).then(result => {
              })
            })
          })
        })
      })
    })
  })
}

I want to do something like that :

this.myScan();
this.myConnect();
this.myNotification();
this.myMessage('Text 1');
this.myMessage('Text 2');
this.myMessage('Text X');

The probleme : My function ‘myConnect‘ don't wait the end of ‘myScan‘ to start. So somme stuff needed by ‘myConnect‘ is do in ‘myScan‘.

I already try to use ‘async/await‘ but does not work. I think i don't use it correctly :

 await this.myConnect().then(async () => {
       await this.myNotification().then(async () => {
           await this.myMessage('03020000').then(async () => {
               await this.myMessage('010100').then(async () => {
                   await this.myMessage('020200' + this.random.toString(16));
               });
           });
       });
   });

Help me to understand how to create a function who wait the end of the before one to start :D

Upvotes: 4

Views: 1288

Answers (6)

Jim Buck
Jim Buck

Reputation: 2444

You're so close! Rather than using .then and async just use one or the other. Here are a few ways to accomplish what you are trying to do:

Using .then:

This is your typical chaining syntax. Promises can be chained using .then() and passing in a function. If the return value is a value (not a Promise) then it will resolve to that value. But if it did return a Promise then it will chain together and your next .then() will resolve to the "inner" async call result.

// Message 1
return this.ble.writeWithoutResponse(infos, message).then(result1 => {
  // Message 2
  return this.ble.writeWithoutResponse(infos, message);
}).then(result2 => { 
  // Message 3
  return this.ble.writeWithoutResponse(infos, message);
)}.then(result3 => {
  // Message X
  return this.ble.writeWithoutResponse(infos, message);
}).then(result4 => {  })

Using async/await

This approach achieves the same result but uses special keywords to automatically chain promises together. async/await allows you to skip the .then() and return calls so you can invoke your async functions as if they were synchronous.

// Message 1
let result1 = await this.ble.writeWithoutResponse(infos, message)
// Message 2
let result2 = await this.ble.writeWithoutResponse(infos, message);
// Message 3
let result3 = await this.ble.writeWithoutResponse(infos, message);
// Message X
let result4 = await this.ble.writeWithoutResponse(infos, message);

To learn more about Promise's and async javascript, check out these resources:

Upvotes: 0

AVJT82
AVJT82

Reputation: 73357

I would embrace Observables. Looking at what you want..

  1. Search Device around me
  2. Connect to this device
  3. Activate Notification
  4. Send Messages

1 and 2 would be chained with switchMap, as responses depend on each other. Then 3 and 4 could be performed in order, but not dependent on each other, therefore we could use concat with those. (If this is not correct flow, adjust accordingly with these two operators).

So I suggest the following:

import { never } from 'rxjs';
import { switchMap, concat } from 'rxjs/operators';

// ...

this.ble.scan().pipe(
  switchMap((device) => {
    if (device === theDeviceIWant) { 
      return this.ble.connect(device.id)
    }
    // terminates rest of code
    return never();
  }),
  concat(
    this.ble.startNotification(...),
    this.ble.writeWithoutResponse(...)
  )
).subscribe(data => console.log(data))

Upvotes: 0

Tom O.
Tom O.

Reputation: 5941

This is essentially what Promises are made for.

A Promise is an object representing the eventual completion or failure of an asynchronous operation.

You can read up about Promises here. Once you read thru that, I left an example for you below to demonstrate how to use a Promise:

//Wrap the operation you want to wait for in a Promise (in this case: setTimeout)
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('3 seconds have passed');
  }, 3000);
});

//Once the operation is resolved the callback in the .then will be called
promise.then(val => document.querySelector('#target').innerHTML = val);
<div id="target">This message will change once the operation is resolved in 3 seconds.</div>

Upvotes: 0

Saurabh Yadav
Saurabh Yadav

Reputation: 3386

The keyword await makes JavaScript wait until that promise settles and returns its result.

So you dont need to use then in await this.myConnect().then(()=>{});

use await this.myConnect();

Below is example which help you understand better

function SignalOne() {

        return new Promise((resolve, reject) => {
            setTimeout(()=>{
                resolve('Hello iam signal one');
            }, 2000);
        });

    }

    function SignalTwo() {

        return new Promise((resolve, reject) => {
            setTimeout(()=>{
                resolve('Hello iam signal Two');
            }, 1000);
        });

    }

    async function sendSignal() {
        let one = await SignalOne();
        let two = await SignalTwo();
        console.log(one);
        console.log(two);

    }

    sendSignal();

Upvotes: 2

Josh Lind
Josh Lind

Reputation: 126

Try this:

async myScan() {
   // do things
}

ngOnInit() {
   const scan = this.myScan(); // myScan doesn't actually have to return here
   await scan;
   const connect = this.myConnect();
   await connect;
   // more stuff
}

Upvotes: 0

hansmaad
hansmaad

Reputation: 18905

Just use async/await OR then

 await this.myConnect();  // this awaits the Promise returned by myConnect to be resolved
 await this.myNotification();  // same for this Promise
 await this.myMessage('03020000');  // and so on...
 await this.myMessage('010100');
 await this.myMessage('020200' + this.random.toString(16));

Upvotes: 5

Related Questions