TL;DR
N'utilisez pas le modèle en question où vous obtenez les promesses, et puis séparément attendre sur eux; au lieu de cela, utilisez Promise.all
(au moins pour l'instant):
const [value1, value2] = await Promise.all([getValue1Async(), getValue2Async()]);
Alors que votre solution ne faire fonctionner les deux opérations en parallèle, il ne gère pas le rejet correctement si les deux promet de le rejeter.
Détails:
Votre solution fonctionne en parallèle, mais attend toujours le premier à terminer avant l'attente de la seconde. Si vous voulez juste pour démarrer, exécuter en parallèle, et d'obtenir les deux résultats, il suffit bien. (Non, ce n'est pas le cas, continuez à lire...) Notez que si le premier prend, disons, cinq secondes et le second échoue dans une seconde, votre code d'attendre les cinq secondes avant la faute.
Malheureusement, il n'y a pas actuellement de l' await
de la syntaxe pour faire un parallèle attendre, alors vous avez l'embarras que vous avez énumérés, ou Promise.all
. (Il y a eu une discussion d' await.all
ou similaire, bien que, peut-être un jour.)
L' Promise.all
version est:
const [value1, value2] = await Promise.all([getValue1Async(), getValue2Async()]);
...ce qui est plus concis, et aussi ne pas attendre que la première opération à réaliser si le second ne parvient pas rapidement (par exemple, dans mes cinq secondes / un deuxième exemple ci-dessus, au-dessus de la rejeter dans un deuxième plutôt que d'attendre cinq). Notez également qu'avec votre code d'origine, si la deuxième promesse rejette avant la première promesse se résout, vous pouvez ainsi obtenir un "non gérée rejet" erreur dans la console (vous n'avez actuellement avec Chrome v61), bien que cette erreur est sans doute fausse (parce que vous n', éventuellement, gérer le rejet). Mais si les deux promesses de rejeter, vous obtiendrez un véritable non gérée rejet d'erreur parce que le flux de contrôle n'atteint jamais l' const value2 = await p2;
et donc la p2 rejet n'est jamais traitée.
Non gérée rejets sont une Mauvaise Chose™ (tant et si bien que bientôt, NodeJS va annuler le processus de vraiment non gérée rejet, tout comme les exceptions non gérées — parce que c'est ce qu'ils sont), donc il vaut mieux éviter les "obtenir la promesse alors await
il" motif dans votre question.
Voici un exemple de la différence de timing dans le cas d'échec (à l'aide de 500ms et 100ms plutôt que 5 secondes et 1 seconde), et, éventuellement aussi, sans doute-faux non gérée rejet d'erreur (ouvert le réel navigateur de la console pour voir):
const getValue1Async = () => {
return new Promise(resolve => {
setTimeout(resolve, 500, "value1");
});
};
const getValue2Async = () => {
return new Promise((resolve, reject) => {
setTimeout(reject, 100, "error");
});
};
// This waits the full 500ms before failing, because it waits
// on p1, then on p2
(async () => {
try {
console.time("separate");
const p1 = getValue1Async();
const p2 = getValue2Async();
const value1 = await p1;
const value2 = await p2;
} catch (e) {
console.error(e);
}
console.timeEnd("separate");
})();
// This fails after just 100ms, because it doesn't wait for p1
// to finish first, it rejects as soon as p2 rejects
setTimeout(async () => {
try {
console.time("Promise.all");
const [value1, value2] = await Promise.all([getValue1Async(), getValue2Async()]);
} catch (e) {
console.timeEnd("Promise.all", e);
}
}, 1000);
Open the real browser console to see the unhandled rejection error.
Et ici, nous rejeter à la fois p1
et p2
, résultant en une non-faux non gérée rejet d'erreur sur p2
:
const getValue1Async = () => {
return new Promise((resolve, reject) => {
setTimeout(reject, 500, "error1");
});
};
const getValue2Async = () => {
return new Promise((resolve, reject) => {
setTimeout(reject, 100, "error2");
});
};
// This waits the full 500ms before failing, because it waits
// on p1, then on p2
(async () => {
try {
console.time("separate");
const p1 = getValue1Async();
const p2 = getValue2Async();
const value1 = await p1;
const value2 = await p2;
} catch (e) {
console.error(e);
}
console.timeEnd("separate");
})();
// This fails after just 100ms, because it doesn't wait for p1
// to finish first, it rejects as soon as p2 rejects
setTimeout(async () => {
try {
console.time("Promise.all");
const [value1, value2] = await Promise.all([getValue1Async(), getValue2Async()]);
} catch (e) {
console.timeEnd("Promise.all", e);
}
}, 1000);
Open the real browser console to see the unhandled rejection error.
Dans un commentaire vous avez demandé:
Côté question: est-ce la force en attente pour les deux (et de rejeter les résultats) await p1 && await p2
?
Cela a le même questions autour de la promesse de rejet de votre code d'origine: Il faudra patienter jusqu' p1
résout même si p2
rejette plus tôt; il peut générer une sans doute-faux non gérée rejet d'erreur si p2
rejette avant d' p1
résout; et il génère un véritable non gérée rejet d'erreur si les deux p1
et p2
de rejet (parce qu' p2
s'rejet n'est jamais manipulée).
Voici le cas où l' p1
résout et p2
dénonce:
const getValue1Async = () => {
return new Promise(resolve => {
setTimeout(resolve, 500, false);
});
};
const getValue2Async = () => {
return new Promise((resolve, reject) => {
setTimeout(reject, 100, "error");
});
};
(async () => {
try {
const p1 = getValue1Async();
const p2 = getValue2Async();
console.log("waiting");
await p1 && await p2;
} catch (e) {
console.error(e);
}
console.log("done waiting");
})();
Look in the real console (for the unhandled rejection error).
...et où les deux rejetons:
const getValue1Async = () => {
return new Promise((resolve, reject) => {
setTimeout(reject, 500, "error1");
});
};
const getValue2Async = () => {
return new Promise((resolve, reject) => {
setTimeout(reject, 100, "error2");
});
};
(async () => {
try {
const p1 = getValue1Async();
const p2 = getValue2Async();
console.log("waiting");
await p1 && await p2;
} catch (e) {
console.error(e);
}
console.log("done waiting");
})();
Look in the real console (for the unhandled rejection error).