Vnořených databázových volání se můžete zbavit pomocí sliby
.
Protože jste zmínili, že používáte mysql
knihovna pro interakci s databází, bohužel tato knihovna neposkytuje API založené na slibech. Chcete-li se tedy zbavit vnořených databázových volání ve vašem kódu, musíte vytvořit obal na základě slibů kolem verze zpětného volání databázových volání.
Obecný přehled o tom, co jsou sliby a jak fungují, naleznete na následujících odkazech:
Následuje příklad toho, jak můžete vytvořit obal na základě slibů a poté jej použít k odstranění vnořených databázových volání.
Tento obal na základě slibu je pouze funkcí, která vrací slib. Vytvoří instanci slibu, zabalí základní volání databáze a nakonec, když volání databáze vrátí data, upozorní váš kód.
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);
});
});
}
Nyní ve funkci obslužné rutiny trasy, místo volání db.cats(...)
, nazvěte to getCats
funkce wrapper.
Existují dva způsoby, jak můžete zavolat funkci, která vrací slib:
Promise-chaining
(Podrobnosti naleznete na výše uvedených odkazech)async-await
syntaxe (doporučeno)
Následující příklad kódu používá async-await
syntax. Nejprve označte funkci obslužné rutiny trasy jako asynchronní
pomocí asynchronního
klíčové slovo před funkcí
klíčové slovo. K tomu můžeme použít wait
klíčové slovo uvnitř této funkce ovladače trasy.
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
}
});
Výše uvedený příklad kódu pouze ukazuje, jak zabalit db.cats(...)
volání databáze v wrapperu založeném na slibech a použijte tento wrapper k získání dat z databáze. Podobně můžete vytvořit obaly pro db.dogs(...)
a db.budgies(...)
hovory.
Namísto vytváření samostatného obalu na základě slibu pro každé volání databáze by v ideálním případě měli byste vytvořit znovu použitelnou funkci obalu na základě slibu který přijme funkci k volání a zabalí toto volání funkce do slibu, jak je ukázáno ve výše uvedeném příkladu kódu, tj. getCats
funkce.
Volání paralelní databáze
Ve výše uvedeném kódu ve funkci obslužné rutiny trasy
je třeba poznamenat jednu důležitou věcconst cats = await getCats();
const dogs = await getDogs();
const budgies = await getBudgies();
je, že to povede k sekvenčnímu volání databáze což může nebo nemusí to, co chcete.
Pokud tato databázová volání na sobě nezávisí, můžete obaly založené na slibech volat paralelně pomocí Promise.all()
metoda.
Následující příklad kódu ukazuje, jak můžete paralelně volat své funkce wrapper založené na slibech pomocí 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) {
...
}
});
Doufám, že to stačí k tomu, abyste se zbavili vnořených databázových volání ve vašem aktuálním kódu a začali ve svém kódu používat sliby.