Du kan slippe af med indlejrede databasekald ved at bruge kode>løfter .
Siden du nævnte, at du bruger mysql
bibliotek til at interagere med databasen, desværre giver dette bibliotek ikke en løftebaseret API. Så for at slippe af med indlejrede databasekald i din kode, skal du oprette en løftebaseret indpakning omkring tilbagekaldsversionen af databasekald.
For et generelt overblik over, hvad løfter er, og hvordan de virker, se følgende links:
Følgende er et eksempel på, hvordan du kan oprette en løftebaseret indpakning og derefter bruge denne indpakning til at slippe af med indlejrede databasekald.
Denne løftebaserede indpakning er blot en funktion, der returnerer et løfte. Det opretter en løfteforekomst, ombryder det underliggende databasekald og til sidst, når databasekaldet returnerer dataene, giver det din kode besked.
function getCats() {
return new Promise((resolve, reject) => {
// make the database call
db.cats((error, cats) => {
// in case of an error, reject the promise by
// calling "reject" function
// Also pass the "error" object to the "reject" function
// as an argument to get access to the error message
// in the code that calls this "getCats" function
if (error) {
reject(error);
return;
}
// if there was no error, call "resolve" function
// to resolve the promise. Promise will be resolved
// in case of successful database call
// Also pass the data to "resolve" function
// to access this data in the code that calls this
// "getCats" function
resolve(cats);
});
});
}
Nu i din rutehåndteringsfunktion, i stedet for at kalde db.cats(...)
, kald dette getCats
indpakningsfunktion.
Der er to måder, du kan kalde den funktion, der returnerer et løfte:
Løftekæde
(For detaljer, besøg linkene nævnt ovenfor)async-await
syntaks (anbefalet)
Følgende kodeeksempel bruger async-await
syntaks. Til dette skal du først markere rutehåndteringsfunktionen som async
ved at bruge async
nøgleord før funktionen
søgeord. Når vi gør dette, kan vi bruge await
nøgleord i denne rutehåndteringsfunktion.
app.get('/pets', async function(req, res, next) {
try {
const cats = await getCats();
// similar wrappers for other database calls
const dogs = await getDogs();
const budgies = await getBudgies();
// render the pub template, passing in the data
// fetched from the database
...
catch (error) {
// catch block will be invoked if the promise returned by
// the promise-based wrapper function is rejected
// handle the error appropriately
}
});
Ovenstående kodeeksempel viser kun, hvordan man pakker db.cats(...)
databasekald i en løftebaseret indpakning og brug denne indpakning til at hente data fra databasen. På samme måde kan du oprette wrappers til db.dogs(...)
og db.budgies(...)
opkald.
I stedet for at oprette en separat løftebaseret indpakning for hvert databasekald bør du ideelt set oprette en genbrugelig løftebaseret indpakningsfunktion der tager en funktion til at kalde og omslutter det funktionskald i et løfte ligesom vist i ovenstående kodeeksempel, dvs. getCats
funktion.
Parallelle databasekald
En vigtig ting at bemærke i ovenstående kode i rutehåndteringsfunktionen
const cats = await getCats();
const dogs = await getDogs();
const budgies = await getBudgies();
er, at dette vil føre til sekventielle databasekald som måske eller måske ikke, hvad du ønsker.
Hvis disse databasekald ikke er afhængige af hinanden, kan du kalde de løftebaserede indpakninger parallelt ved hjælp af Promise.all()
metode.
Følgende kodeeksempel viser, hvordan du kan kalde dine løftebaserede indpakningsfunktioner parallelt ved hjælp af Promise.all()
.
app.get('/pets', async function(req, res, next) {
try {
// "petsData" will be an array that will contain all the data from
// three database calls.
const petsData = await Promise.all([getCats(), getDogs(), getBudgies()]);
// render the pub template, passing in the data
// fetched from the database
...
catch (error) {
...
}
});
Jeg håber, at dette er nok til at hjælpe dig med at slippe af med de indlejrede databasekald i din nuværende kode og begynde at bruge løfter i din kode.