web-dev-qa-db-fra.com

ES8 Expression de la fonction asynchrone immédiatement invoquée

Je n'ai pas vu ces constructions utilisées beaucoup mais je me suis retrouvé à les écrire pour utiliser async/wait dans des fonctions qui ne retournent généralement pas de promesse, par exemple

chan.consume(queue, (msg) => {
  this.pendingMsgs++; // executed immediately
  (async () => {
    await this.handleMessage(msg);
    this.pendingMsgs--;
    if (cancelled && this.pendingMsgs === 0) {
       await chan.close();
       await this.amqpConnectionPool.release(conn);
    } 
  })();
});

par opposition à

chan.consume(queue, async (msg) => { // external lib does not expect a return value from this callback
  this.pendingMsgs++;  // executed in promise context(?)
  await this.handleMessage(msg);
  this.pendingMsgs--;
    if (cancelled && this.pendingMsgs === 0) {
       await chan.close();
       await this.amqpConnectionPool.release(conn);
    }
});

ou

chan.consume(queue, (msg) => {
  this.pendingMsgs++;  // no await - excess function decls & nesting
  this.handleMessage(msg).then(() => {
    this.pendingMsgs--;
    if (cancelled && this.pendingMsgs === 0) {
       chan.close().then(() => {
         this.amqpConnectionPool.release(conn);
       });
    }
  });
});

Est-ce "une chose"? Y a-t-il des pièges ici dont je devrais être conscient? Quel est le point bas sur l'utilisation de async/wait dans ce genre de situations?

17
Drew R

Est-ce "une chose"?

Oui. Cela revient de temps en temps, par exemple ici . Ils sont connus comme IIAFE :-)
Si vous voulez mettre l'accent sur la flèche, vous pouvez aussi les appeler IIAAF.

Y a-t-il des pièges ici dont je devrais être conscient?

Chaque fois que vous appelez une fonction de retour de promesse et que vous ne renvoyez pas le résultat ailleurs, vous êtes vous-même responsable de la promesse - ce qui signifie que vous devez en gérer les erreurs. Donc, le motif devrait en général ressembler à

(async () => {
    …
})().catch(err => {
    console.error(err);
});

si vous ne voulez pas vous préoccuper des événements de rejet non gérés.

Quel est le point bas sur l'utilisation de async/await dans ce genre de situations?

Pas grand-chose, comparé à la version then. Cependant, vous dites " la bibliothèque externe n'attend pas de valeur de retour de ce rappel ", ce qui pourrait faire allusion à l'incompatibilité de la bibliothèque avec les rappels asynchrones, alors méfiez-vous ce que vous faites quand. Cela peut également dépendre des exceptions lancées de manière synchrone à partir du rappel, donc tout dépend de ce que la bibliothèque attend ici (et s'il n'y a aucune attente, si cela peut changer à l'avenir). Vous ne voulez pas d'incompatibilités futures au cas où la bibliothèque commencerait à traiter spécialement les valeurs de retour promises.

Cependant, je recommanderais toujours le deuxième modèle qui passe directement la fonction async directement comme rappel en raison de sa meilleure lisibilité. Si vous voulez éviter de renvoyer une promesse à la bibliothèque, créez une fonction d'assistance qui encapsule le rappel:

function toVoid(fn) {
    return (...args) => void fn(...args);
}
function promiseToVoid(fn) {
    return (...args) => void fn(...args).catch(console.error);
}

que vous pourriez utiliser comme ceci:

chan.consume(queue, toVoid(async (msg) => {
     … // use `await` freely
}));
34
Bergi