Изглежда, че тук има известно объркване относно това как да използвате правилно Promises на няколко нива.
Обратното повикване и обещанието се използват неправилно
Ако функцията трябва да приеме обратно извикване, не връщайте Promise. Ако функцията трябва да върне Promise, използвайте обратното извикване, дадено от 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")
}
});
})
Нека разгледаме това по-подробно:
return new Promise( (resolve, reject) => {
Това създава ново Promise и Promise ви дава две обратни извиквания за използване. resolve
е обратно извикване, което показва успех. Предавате му обекта, който искате да върнете. Имайте предвид, че премахнах async
ключова дума (повече за това по-късно).
Например:
const a = new Promise( (resolve, reject) => resolve(5) );
a.then( (result) => result == 5 ); //true
(err, testData) => {
Тази функция се използва за картографиране на стила на възел cb(err, result)
към обратните извиквания на Promise.
Try/catch се използват неправилно.
Try/catch може да се използва само за синхронни изрази. Нека сравним синхронно повикване, стил на възел (т.е. cb(err, result)
) асинхронно обратно извикване, обещание и използване на await:
- Синхронно:
try {
let a = doSomethingSync();
} catch(err) {
handle(err);
}
- Асинхронен:
doSomethingAsync( (err, result) => {
if (err) {
handle(err);
} else {
let a = result;
}
});
- Обещание:
doSomethingPromisified()
.then( (result) => {
let a = result;
})
.catch( (err) => {
handle(err);
});
- Изчакайте. Await може да се използва с всяка функция, която връща Promise и ви позволява да боравите с кода, сякаш е синхронен:
try {
let a = await doSomethingPromisified();
} catch(err) {
handle(err);
}
Допълнителна информация
Promise.resolve()
Promise.resolve()
създава ново обещание и разрешава това обещание с недефинирана стойност. Това е съкращение за:
new Promise( (resolve, reject) => resolve(undefined) );
Еквивалентът на обратното извикване на това би бил:
cb(err, undefined);
async
async
върви с await
. Ако използвате await
във функция тази функция трябва да бъде декларирана като async
.
Точно като await
разгръща Promise (resolve
в стойност и reject
в изключение), async
обвивки кодирайте в обещание. return value
операторът се превежда в Promise.resolve(value)
и хвърлено изключение throw e
се превежда в Promise.reject(e)
.
Разгледайте следния код
async () => {
return doSomethingSync();
}
Кодът по-горе е еквивалентен на този:
() => {
const p = new Promise(resolve, reject);
try {
const value = doSomethingSync();
p.resolve(value);
} catch(e) {
p.reject(e);
}
return p;
}
Ако извикате някоя от горните функции без await
, ще получите обратно обещание. Ако await
който и да е от тях, ще ви бъде върната стойност или ще бъде хвърлено изключение.