Pracuję nad Ionic v4 z Angular.
W moim projekcie używam BLE do komunikacji z maliną.
Mam kilka kroków:
- Wyszukaj urządzenie wokół mnie
- Połącz się z tym urządzeniem
- Aktywuj powiadomienie
- Wysłać wiadomości
Obecnie mam coś takiego:
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 => {
})
})
})
})
})
})
})
}
Chcę zrobić coś takiego:
this.myScan();
this.myConnect();
this.myNotification();
this.myMessage('Text 1');
this.myMessage('Text 2');
this.myMessage('Text X');
Problem: Moja funkcja „myConnect” nie czeka na uruchomienie końca „myScan”. Tak więc niektóre rzeczy potrzebne „myConnect” są dostępne w „myScan”.
Próbuję już użyć „async / await”, ale nie działa. Myślę, że nie używam go poprawnie:
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));
});
});
});
});
Pomóż mi zrozumieć, jak stworzyć funkcję, która czeka na koniec poprzedniej: D
6 odpowiedzi
Po prostu użyj async / await LUB 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));
Słowo kluczowe await sprawia, że JavaScript czeka, aż obietnica się spełni i zwróci wynik.
Nie musisz więc używać then
i await this.myConnect().then(()=>{});
Użyj await this.myConnect()
;
Poniżej znajduje się przykład, który pomoże Ci lepiej zrozumieć
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();
Spróbuj tego:
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
}
To jest zasadniczo to, do czego są stworzone Promises.
Promise to obiekt reprezentujący ostateczne zakończenie lub niepowodzenie operacji asynchronicznej.
Tutaj możesz przeczytać o obietnicach. Kiedy już to przeczytasz, zostawiłem dla ciebie przykład poniżej, aby zademonstrować, jak używać 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>
Przyjąłbym Observables. Patrzę na to, czego chcesz ...
- Wyszukaj urządzenie wokół mnie
- Połącz się z tym urządzeniem
- Aktywuj powiadomienie
- Wysłać wiadomości
1 i 2 byłyby połączone z switchMap
, ponieważ odpowiedzi zależą na siebie. Wtedy 3 i 4 mogłyby być wykonane w kolejności, ale nie zależne od siebie, dlatego moglibyśmy użyć concat
z nimi. (Jeśli to nie jest prawidłowy przepływ, dostosuj odpowiednio za pomocą tych dwóch operatorów).
Sugeruję więc:
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))
Jesteś tak blisko! Zamiast używać .then
i async
po prostu użyj jednego lub drugiego. Oto kilka sposobów na osiągnięcie tego, co próbujesz zrobić:
Korzystanie z .then
:
To jest twoja typowa składnia tworzenia łańcuchów. Obietnice można łączyć za pomocą .then()
i przekazując funkcję. Jeśli zwracana wartość jest wartością (nie Promise
), to zostanie rozwiązana do tej wartości. Ale jeśli zwrócił Promise
, zostanie połączony, a następne .then()
przekształci się w „wewnętrzny” wynik wywołania asynchronicznego.
// 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 => { })
Za pomocą async
/ await
Takie podejście pozwala osiągnąć ten sam wynik, ale wykorzystuje specjalne słowa kluczowe, aby automatycznie łączyć ze sobą obietnice. async
/await
pozwala pominąć wywołania .then()
i return
, dzięki czemu można wywołać funkcje asynchroniczne tak, jakby były synchroniczne.
// 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);
Aby dowiedzieć się więcej o Promise
i async javascript, zapoznaj się z tymi zasobami:
- Obietnice na MDN
- Obietnice dotyczące Google Web Fundamentals
- Wideo na temat asynchroniczności/oczekiwania