2
votes

Comment attendre une fonction asynchrone en javascript au plus haut niveau?

Je sais que c'est une idée terrible. Mais j'ai une API que je ne peux pas utiliser tant que je n'ai pas une donnée que je ne peux obtenir que de manière asynchrone. Quelque chose comme ceci:

import API from '@/api'

const key = async get_key() // NOPE
const theAPI = new API(key)

async importantMethod(args)
{
  return await theAPI.f1(args)
}
async otherMethod()
{
  if (theAPI.f3)
    return await theAPI.f2(123)
  // etc...
}
// ... and so on

C'est au plus haut niveau, en dehors de toute fonction, donc je ne peux pas simplement attendre get_async_data () (il renvoie une promesse). Y a-t-il quelque chose à part de mettre tout mon code dans une fonction asynchrone géante pour que je puisse appeler await?

API est juste une classe exportée par un module (que je contrôle).

(BTW, j'ai pensé à mettre le code pour obtenir la clé dans le constructeur de la classe API , mais bien sûr, les constructeurs ne peuvent pas non plus être asynchrones.)

Je pourrais faire en sorte que chaque méthode asynchrone de l ' API définisse la clé si elle n'est pas définie, mais c'est assez invasif et sujet aux erreurs.

Donc, je ne demande pas vraiment comment faire mon top- le code de niveau attendez autant que je cherche des moyens alternatifs de structurer cela pour que l'appel async se passe proprement.

Voici quelques détails supplémentaires au cas où cela aiderait. Dans api.js:

class API {
  constructor(key) {
    this.key = key
    // other stuff
  }
  async f1(a) {
  }
  async f2(b, c) {
  }
  f3() {
    return true
  }
}
export default API

Puis aux endroits (nombreux) où il sera utilisé:

const key = await get_async_data(config) // NOT RIGHT, can't use await at top level
const api = new API(key)
... use api ...


6 commentaires

Pouvez-vous expliquer le problème que vous rencontrez avec l'encapsulation du code dans une fonction async (ou simplement en utilisant .then )? Cela semble être la solution évidente


Je souhaite utiliser cette API partout, dans toutes mes classes. Je ne peux pas tout envelopper dans une fonction asynchrone géante.


Vous ne savez pas ce que vous voulez dire, mais vous devrez attendre cette fonction partout où vous devez attendre que la promesse se résout avant de continuer. Ou si vous ne voulez pas tout envelopper dans une fonction asynchrone, utilisez simplement .then à la place.


Pouvez-vous donner un exemple plus concret avec plus de code, afin que nous puissions voir ce qui vous semble trop compliqué? Ce n'est pas tout à fait clair ATM


Appelez simplement l'API, remplissez la promesse résultante dans un var et attendez si nécessaire.


@JaredSmith avec les détails supplémentaires que j'ai ajoutés, pouvez-vous expliquer comment cela fonctionnerait dans mon cas?


3 Réponses :


0
votes

Le niveau supérieur est une idée terrible, oui. Mais je ne vois pas pourquoi vous ne pouvez pas simplement le mettre dans une fonction?

const getAsync = async () => {
  const key = await get_async_data(config);
  return key;
}
getAsync().then(key => {
  const api = new API(key)
}


6 commentaires

Pas besoin de wait / async si vous utilisez .then , faites simplement get_async_data (config) .then (key =>


De plus, ce n'est pas tant une "mauvaise idée" (ce n'est pas une mauvaise idée, il y a actuellement une proposition pour await de niveau supérieur) qu'une idée qui n'est actuellement pas autorisée par la spécification.


bien sûr, mais il semble vouloir une fonction plus petite disponible pour une utilisation ailleurs. Peut-être pour impliquer d'autres paramètres? et que ce soit juste une pure promesse ou écrit comme une attente asynchrone n'est ni ici ni là.


re proposition, je ne savais pas ça, intéressant. Je dirais toujours que faire des fonctionnalités dans le monde entier est généralement à éviter, mais je comprends qu'il existe d'autres points de vue à ce sujet. J'imagine que le niveau supérieur attendre le ferait sentir un peu plus PHP / Python-y.


Le niveau supérieur d'un projet ne signifie pas nécessairement global, heureusement - c'est à cela que servent les bundleurs de modules.


vrai, mais semble toujours être une manière inutilement obtuse de faire les choses.



0
votes

Utilisez simplement la promesse:

import pendingAPI from 'other/file';
pendingAPI.then(doStuffWithAPI);

En attendant, dans un autre fichier ...

const pendingAPI = get_async_data(config).then(key => new API(key)); // N.B. no await
export default pendingAPI;

Il y a des moments où asynchrone / wait est une victoire. Mais n'oubliez jamais que c'est juste du sucre sur les promesses.


0 commentaires

0
votes

Si vous voulez modifier le moins possible votre code existant, j'envisagerais de changer le point d'entrée en un module qui récupère la clé, puis d'appeler le module qui instancie l'API (l'ancien point d'entrée). Par exemple:

// start.js
import makeApi from './makeApi';
get_key()
  .then(makeApi);

// makeApi.js
export default function(key) {
  const theApi = new API(key);
  function importantMethod(args) {
    return theAPI.f1(args)
  }
  function otherMethod() {
    if (theAPI.f3)
      return theAPI.f2(123)
  }
  // etc
}

En bref, tout ce que vous avez à faire est d'encapsuler votre point d'entrée actuel dans une fonction.


0 commentaires