Wygląda na to, że istnieje pewne zamieszanie co do tego, jak prawidłowo używać obietnic na kilku poziomach.
Oddzwanianie i obietnica są używane nieprawidłowo
Jeśli funkcja ma akceptować wywołanie zwrotne, nie zwracaj Promise. Jeśli funkcja ma zwrócić Promise, użyj wywołania zwrotnego podanego przez Promise:
const transactionSession = await mongoose.startSession()
await transactionSession.withTransaction( (tSession) => {
return new Promise( (resolve, reject) => {
//using Node-style callback
doSomethingAsync( (err, testData) => {
if(err) {
reject(err);
} else {
resolve(testData); //this is the equivalent of cb(null, "Any test data")
}
});
})
Przyjrzyjmy się temu bardziej szczegółowo:
return new Promise( (resolve, reject) => {
W ten sposób powstaje nowa Promise, która daje dwa wywołania zwrotne do użycia. resolve
jest wywołaniem zwrotnym wskazującym sukces. Podajesz mu przedmiot, który chcesz zwrócić. Zauważ, że usunąłem async
słowo kluczowe (więcej na ten temat później).
Na przykład:
const a = new Promise( (resolve, reject) => resolve(5) );
a.then( (result) => result == 5 ); //true
(err, testData) => {
Ta funkcja służy do mapowania stylu węzła cb(err, result)
do wywołań zwrotnych Obietnicy.
Try/catch są używane nieprawidłowo.
Try/catch może być używany tylko w przypadku instrukcji synchronicznych. Porównajmy wywołanie synchroniczne, styl Node (np. cb(err, result)
) asynchroniczne wywołanie zwrotne, obietnica i użycie await:
- Synchroniczne:
try {
let a = doSomethingSync();
} catch(err) {
handle(err);
}
- Asynchronizacja:
doSomethingAsync( (err, result) => {
if (err) {
handle(err);
} else {
let a = result;
}
});
- Obietnica:
doSomethingPromisified()
.then( (result) => {
let a = result;
})
.catch( (err) => {
handle(err);
});
- Czekaj. Await może być używany z dowolną funkcją, która zwraca obietnicę i pozwala obsługiwać kod tak, jakby był synchroniczny:
try {
let a = await doSomethingPromisified();
} catch(err) {
handle(err);
}
Dodatkowe informacje
Promise.resolve()
Promise.resolve()
tworzy nową Obietnicę i rozwiązuje tę Obietnicę z niezdefiniowaną wartością. To jest skrót od:
new Promise( (resolve, reject) => resolve(undefined) );
Odpowiednikiem tego wywołania zwrotnego byłoby:
cb(err, undefined);
async
async
idzie z await
. Jeśli używasz await
w funkcji, ta funkcja musi być zadeklarowana jako async
.
Tak jak await
odpakowuje obietnicę (resolve
na wartość i reject
do wyjątku), async
zawija kod do obietnicy. return value
instrukcja zostaje przetłumaczona na Promise.resolve(value)
i zgłoszony wyjątek throw e
zostanie przetłumaczony na Promise.reject(e)
.
Rozważ następujący kod
async () => {
return doSomethingSync();
}
Powyższy kod jest odpowiednikiem tego:
() => {
const p = new Promise(resolve, reject);
try {
const value = doSomethingSync();
p.resolve(value);
} catch(e) {
p.reject(e);
}
return p;
}
Jeśli wywołasz jedną z powyższych funkcji bez await
, otrzymasz z powrotem obietnicę. Jeśli await
którykolwiek z nich, zostanie zwrócona wartość lub zostanie zgłoszony wyjątek.