Première différence de l'échec rapide
Je suis d'accord avec @zzzzBov de la réponse, mais "fail fast" l'avantage de la Promesse.tout n'est pas seulement une différence. Certains utilisateurs dans les commentaires se demande pourquoi pour utilisation Promesse.lorsqu'il est seulement plus rapide dans le scénario négatif (quand une tâche échoue). Et je me demande pourquoi pas? Si j'ai deux indépendants async et de tâches parallèles premier est résolu dans très longtemps, mais la deuxième est rejeté dans très peu de temps pourquoi laisser l'utilisateur d'attendre mesage d'erreur "très longtemps" au lieu de "très court laps de temps"? Dans des applications réelles, nous devons considérer scénario négatif. Mais OK - dans cette première différence, vous pouvez décider alternative à l'utilisation de la Promesse.tous vs multiples vous attendent.
Deuxième différence d'erreur de manipulation
Mais lorsque l'on considère la gestion d'erreur, VOUS DEVEZ utiliser Promesse.tous les. Il n'est pas possible de gérer correctement les erreurs de async tâches en parallèle déclenchée avec de multiples vous attendent. Dans le scénario négatif, vous allez toujours à la fin avec UnhandledPromiseRejectionWarning
et PromiseRejectionHandledWarning
même si vous utiliser try/catch n'importe où. C'est pourquoi la Promesse.tout a été conçu. Bien entendu, quelqu'un pourrait dire qu'on peut supprimer que les erreurs à l'aide de process.on('unhandledRejection', err => {})
et process.on('rejectionHandled', err => {})
mais il n'est pas une bonne pratique. J'ai trouvé de nombreux exemples sur internet qui ne considère pas de gestion d'erreur pour deux ou plus indépendants async tâches en parallèle à tous ou à envisager, mais dans le mauvais sens - juste à l'aide de try/catch et en espérant qu'il va rattraper les erreurs. Il est presque impossible de trouver une bonne pratique. C'est pourquoi je suis en train d'écrire cette réponse.
Résumé
Ne jamais utiliser de multiples attendent à deux ou plus indépendants async tâches en parallèle parce que vous ne sera pas en mesure de gérer les erreurs au sérieux. Utilisez toujours des Promesses.tous les() pour ce cas d'utilisation.
Async/await n'est pas de remplacement pour des Promesses. Il est juste assez de la manière d'utiliser des promesses... async code est écrit dans la synchronisation de style et on peut éviter de multiples then
dans les promesses.
Certaines personnes disent que l'utilisation de la Promesse.tous les() nous ne pouvons pas gérer les tâches erreurs séparément mais seulement d'erreur de première rejeté promesse (oui, certains cas peuvent nécessiter de traitement distincte par exemple, pour l'enregistrement). Il n'est pas un problème - voir "Plus" de la rubrique ci-dessous.
Exemples
Considérer cette tâche asynchrone...
const task = function(taskNum, seconds, negativeScenario) {
return new Promise((resolve, reject) => {
setTimeout(_ => {
if (negativeScenario)
reject(new Error('Task ' + taskNum + ' failed!'));
else
resolve('Task ' + taskNum + ' succeed!');
}, seconds * 1000)
});
};
Lorsque vous exécutez des tâches dans le scénario positif il n'y a pas de différence entre les Promesses.tous et plusieurs attendent. Les deux exemples de la fin avec Task 1 succeed! Task 2 succeed!
après 5 secondes.
// Promise.all alternative
const run = async function() {
// tasks run immediate in parallel and wait for both results
let [r1, r2] = await Promise.all([
task(1, 5, false),
task(2, 5, false)
]);
console.log(r1 + ' ' + r2);
};
run();
// at 5th sec: Task 1 succeed! Task 2 succeed!
// multiple await alternative
const run = async function() {
// tasks run immediate in parallel
let t1 = task(1, 5, false);
let t2 = task(2, 5, false);
// wait for both results
let r1 = await t1;
let r2 = await t2;
console.log(r1 + ' ' + r2);
};
run();
// at 5th sec: Task 1 succeed! Task 2 succeed!
Lors de la première tâche prend 10 secondes dans le scénario positif et secondes tâche prend que 5 secondes dans le scénario négatif, il existe des différences dans les erreurs émises.
// Promise.all alternative
const run = async function() {
let [r1, r2] = await Promise.all([
task(1, 10, false),
task(2, 5, true)
]);
console.log(r1 + ' ' + r2);
};
run();
// at 5th sec: UnhandledPromiseRejectionWarning: Error: Task 2 failed!
// multiple await alternative
const run = async function() {
let t1 = task(1, 10, false);
let t2 = task(2, 5, true);
let r1 = await t1;
let r2 = await t2;
console.log(r1 + ' ' + r2);
};
run();
// at 5th sec: UnhandledPromiseRejectionWarning: Error: Task 2 failed!
// at 10th sec: PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
// at 10th sec: UnhandledPromiseRejectionWarning: Error: Task 2 failed!
Nous devrions déjà remarquer ici que nous faisons quelque chose de mal lors de l'utilisation de plusieurs attendent en parallèle. Bien sûr, pour éviter des erreurs, nous devons le gérer! Laissez-vous tenter...
// Promise.all alternative
const run = async function() {
let [r1, r2] = await Promise.all([
task(1, 10, false),
task(2, 5, true)
]);
console.log(r1 + ' ' + r2);
};
run().catch(err => { console.log('Caught error', err); });
// at 5th sec: Caught error Error: Task 2 failed!
Comme vous pouvez le voir pour gérer avec succès d'erreur nous avons besoin d'ajouter des captures d' run
de la fonction et le code avec des captures logique est dans le rappel (async style). Nous n'avons pas besoin de gérer les erreurs à l'intérieur d' run
fonctionner, car la fonction async il le fait automatiquement - la promesse de rejet de l' task
fonction provoque le rejet de l' run
fonction. Pour éviter de rappel, nous pouvons utiliser la synchronisation de style (async/await + try/catch) try { await run(); } catch(err) { }
, mais dans cet exemple, il n'est pas possible car nous ne pouvons pas utiliser await
dans le thread principal peut être utilisé uniquement en fonction async (c'est logique parce que personne ne veut bloquer le thread principal). Pour tester si la manipulation fonctionne en synchronisation de style , nous pouvons l'appeler run
fonction à partir d'une autre fonction async ou de l'utilisation IIFE (Immédiatement appelé la Fonction de l'Expression): (async function() { try { await run(); } catch(err) { console.log('Caught error', err); }; })();
.
C'est une seule bonne façon d'exécuter deux ou plusieurs async tâches en parallèle et gérer les erreurs. Vous devriez éviter les exemples ci-dessous.
// multiple await alternative
const run = async function() {
let t1 = task(1, 10, false);
let t2 = task(2, 5, true);
let r1 = await t1;
let r2 = await t2;
console.log(r1 + ' ' + r2);
};
Nous pouvons essayer de manipuler le code au-dessus de plusieurs façons...
try { run(); } catch(err) { console.log('Caught error', err); };
// at 5th sec: UnhandledPromiseRejectionWarning: Error: Task 2 failed!
// at 10th sec: UnhandledPromiseRejectionWarning: Error: Task 2 failed!
// at 10th sec: PromiseRejectionHandledWarning: Promise rejection was handled
... rien n'a été pris car il gère la synchronisation de code, mais run
est asynchrone
run().catch(err => { console.log('Caught error', err); });
// at 5th sec: UnhandledPromiseRejectionWarning: Error: Task 2 failed!
// at 10th sec: Caught error Error: Task 2 failed!
// at 10th sec: PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
... Wtf? Nous voyons d'abord que l'erreur pour la tâche 2 n'a pas été manipulés et, plus tard, qui a été attrapé. Trompeuse et encore plein d'erreurs dans la console. Inutilisable de cette façon.
(async function() { try { await run(); } catch(err) { console.log('Caught error', err); }; })();
// at 5th sec: UnhandledPromiseRejectionWarning: Error: Task 2 failed!
// at 10th sec: Caught error Error: Task 2 failed!
// at 10th sec: PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
... le même que ci-dessus.
const run = async function() {
try {
let t1 = task(1, 10, false);
let t2 = task(2, 5, true);
let r1 = await t1;
let r2 = await t2;
}
catch (err) {
return new Error(err);
}
console.log(r1 + ' ' + r2);
};
run().catch(err => { console.log('Caught error', err); });
// at 5th sec: UnhandledPromiseRejectionWarning: Error: Task 2 failed!
// at 10th sec: PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
... "seulement" deux erreurs (3e est manquant) mais rien attrapé.
Plus (gérer les erreurs de tâches séparément et aussi la première de l'échec d'erreur)
const run = async function() {
let [r1, r2] = await Promise.all([
task(1, 10, true).catch(err => { console.log('Task 1 failed!'); throw err; }),
task(2, 5, true).catch(err => { console.log('Task 2 failed!'); throw err; })
]);
console.log(r1 + ' ' + r2);
};
run().catch(err => { console.log('Run failed (does not matter which task)!'); });
// at 5th sec: Task 2 failed!
// at 5th sec: Run failed (does not matter which task)!
// at 10th sec: Task 1 failed!
... notez que dans cet exemple j'ai utilisé negativeScenario=true pour les deux tâches pour une meilleure démonstration de ce qui se passe (throw err
est utilisé pour le feu final d'erreur)