Chemin de code simple, mieux expliqué avec des puces
Problème
L'étape 5 se produit avant la fin de l'étape 4 (Code ci-dessous)
//api endpoint router.post('/get-data', getObjects); export const getObjects: express.RequestHandler = (req, res) => { queryContainer(containerId, querySpec) .then((result) => { return getChildren(result, req.body.criteria); }) .then((result) => { res.send(result); }); } export async function queryContainer(containerId, querySpec) { const { result: results } = await client.database(databaseId).container(containerId).items.query(querySpec, {enableCrossPartitionQuery: true}).toArray() .catch( (error) => { console.log("Error! ", error); }); return results; } function getChildren(result: any, criteria: any) { if(criteria) { result.children = []; var actions = result .map(result => result.element) .map(dbCallToGetChildren); var results = Promise.all(actions); results.then(children => { result.children.push(...children) return result; }); } return result; } export const dbCallToGetChildren = (async function (username) { const querySpec = { query: "SELECT * FROM root r WHERE r.userName=@userName", parameters: [ {name: "@userName", value: username} ] }; queryContainer(containerId, querySpec) .then((results) => { return results; }) .catch((error) => { console.log("Error " + error); return Promise.resolve; }); });
3 Réponses :
L'étape 5 se produit avant la fin de l'étape 4 (fonction getChildren
) car getChildren
ne renvoie pas de promesse. Le modifier comme suit peut résoudre le problème:
function getChildren(result: any, criteria: any) { return new Promise(resolve => { if(criteria) { result.children = []; var actions = result .map(result => result.element) .map(dbCallToGetChildren); var results = Promise.all(actions); results.then(children => { result.children.push(...children) resolve(result); }); } else { resolve(result); } }); }
Dans results.then (children => {...}
, il y a maintenant resolution (result );
pour garantir que l'instruction return getChildren (result, req.body.criteria);
dans l'appel queryContainer
ne se termine pas tant que la promesse n'est pas résolue.
Pour que l'étape 4 se termine complètement avant que l'étape 5 ne soit exécutée, nous devons promettre chaque chemin de code qui passe par getChildren
.
Cela signifie que nous devons changer ceci: p >
function getChildren(result: any, criteria: any) { if(criteria) { result.children = []; var actions = result .map(result => result.element) .map(dbCallToGetChildren); var results = Promise.all(actions); return results.then(children => { // returns a promise result.children.push(...children) return result; }); } return Promise.resolve(result); // returns a promise }
Dans ce qui suit (faites attention aux commentaires du code):
function getChildren(result: any, criteria: any) { if(criteria) { result.children = []; var actions = result .map(result => result.element) .map(dbCallToGetChildren); var results = Promise.all(actions); results.then(children => { result.children.push(...children) return result; }); } return result; }
Il est important de renvoyer
sinon, le code de cette ligne est exécuté de manière asynchrone (ce qui ne garantit pas que l'étape 4 se terminera avant le début de l'étape 5).
J'ai quelques commentaires sur votre code:
result.children = []
Évitez d'en utiliser et essayez de définir un type
dans votre code parce que vous faites une mutation donc vous n'avez même pas besoin de renvoyer le résultat car l'objet d'origine est déjà modifié mais comme je l'ai mentionné plus tôt, vous devez éviter la mutation.
Le principal problème que l'étape 5 exécute avant l'étape 4 est que getChildren ne retournera pas sa promesse, j'ai apporté quelques modifications à votre code pour tenir compte de la promesse.
function getChildren(result: any, criteria: any): Promise<any> { return new Promise((resolve, reject) => { if (criteria) { result.children = [] const actions = result .map(item => item.element) .map(dbCallToGetChildren) Promise.all(actions).then(children => { // returns a promise result.children.push(...children) return resolve("successfully is processed!") }) } reject("invalid criteria!") }) }
L'ajout de la promesse a résolu le problème. Excellente solution, Mehran.
Dans les mots célèbres de @Bergi (qui a dû le dire 1000 fois), évitez l'anti-modèle de construction de promesse explicite .
@ Roamer-1888 Je suis d'accord avec vous, si je voulais écrire le code, je retournerais toute la promesse au lieu de créer une nouvelle promesse, mais je n'avais pas l'image complète du code et j'ai juste essayé de répondre au question dans un contexte très fermé.