Maison > interface Web > js tutoriel > le corps du texte

Comment créer un constructeur asynchrone en Javascript ?

Susan Sarandon
Libérer: 2024-11-24 03:38:10
original
233 Les gens l'ont consulté

How to make an async constructor in Javascript?

Vous êtes ici car vous avez une question : comment attendre un constructeur de Classe ? Comment rendre le constructeur Async ???

Et la réponse, je suis désolé, est que vous ne pouvez littéralement pas. Un constructeur de classe en Javascript doit être synchrone. Cependant, il existe des alternatives d’implémentation qui peuvent vous aider à faire ce que vous voulez. Explorons-le !

Vous le souhaitez probablement parce que vous devez initialiser quelque chose dans le constructeur et le rendre disponible dans tout appel que vous effectuez à la classe. Un bon exemple serait de se connecter à une base de données et d'attendre que cette connexion soit établie avant d'accepter toute requête.

Le modèle est vraiment simple ! Commençons par un exemple de connecteur de base de données, utilisant le module sqlite sur npm :

import sqlite3 from 'sqlite3';
import { open } from 'sqlite';
Copier après la connexion
Copier après la connexion

Pour ouvrir cette base de données, vous devez attendre la fonction d'ouverture. J'ai demandé à mon sympathique assistant de code IA de créer une classe "DBConnector" et elle a en fait obtenu le bon modèle commun - celui que vous verrez partout :

class DBConnector {
  constructor() {
    this.db = null;
  }

  async connect() {
    this.db = await open({
      filename: './database.sqlite',
      driver: sqlite3.Database,
    });
  }

  async disconnect() {
    await this.db.close();
  }

  async query(sql, params) {
    return this.db.all(sql, params);
  }
}

// exporting a singleton so there's only one connection
export default new DBConnector();
Copier après la connexion

Vous appelleriez cela simplement en l'important puis en attendant ses appels :

import db from './dbconnector.js';

await db.connect();
await db.query('GET * FROM test');
Copier après la connexion

Alors maintenant, le problème ici, bien sûr, est que non seulement vous devez appeler manuellement myDB.connect() afin de démarrer la connexion, mais vous ne pouvez pas non plus garantir que l'appel de requête fonctionnera, par exemple, si un autre fichier effectue une requête pendant que votre fichier principal se connecte.

Bien sûr, le fichier principal peut attendre db.connect(); , mais tout ce qui importe ce module n'aura aucun moyen de le faire. Et vous pourriez penser : « ok mais je peux aussi appeler wait db.connect(); dans d'autres fichiers, n'est-ce pas ? et vous pouvez... mais cela vous reconnectera à la base de données à chaque fois, ce qui peut être lent selon ce que vous utilisez.

Le modèle différé

Le modèle que j'ai proposé implique un peu plus de complexité, mais il reste simple et garantit que chaque petit morceau de code - et vous-même - êtes tous satisfaits. Et je l'ai en fait inventé par moi-même, même si d'autres le savent. On les appelle promesses « différées ».

Voici comment cela fonctionne.

// still have our imports
import sqlite3 from 'sqlite3';
import { open } from 'sqlite';

// Create the class
class DBConnector {
  // We'll need these private properties:
  #db;
  #defer;
  #resolve;
  #reject;
  // Then we make our constructor:
  constructor() {

    // We create a new promise and store its resolve and reject
    // functions in the class instance properties.
    this.#defer = new Promise((res, rej) => {
      // this is the magic, right here, basically.
      this.#resolve = res;
      this.#reject = rej;
    });

    // So now, this.#defer is a promise! We can await it in other methods.
    // Now we call our this.connect *internally* and automatically.
    this.connect();
  }

  async connect() {
    try {
      this.#db = await open({
        filename: `./database.sqlite`,
        driver: sqlite3.Database,
      });
      // Now that we resolve the promise, any other method that awaits
      // this.#defer will continue executing.
      this.#resolve();
    } catch (err) {
      // in case of error we can of course reject the promise
      // any code using it would then throw an error.
      this.#reject(err);
    }
  }

  async disconnect() {
    // on any action, we just await this.#defer
    await this.#defer;
    await this.#db.close();
  }

  async query(sql, params) {
    // Even in queries, it works perfectly fine!
    await this.#defer;
    // Here we KNOW that this.#db is already initialized.
    return this.#db.all(sql, params);
  }
}

export default new DBConnector();
Copier après la connexion

N'est-ce pas un charmant petit motif ? Il s'agit bien sûr plus de code qu'un exemple de base, mais personnellement, je pense que cela place définitivement la barre plus haut en matière de code passe-partout pour les classes qui sont principalement basées sur des méthodes asynchrones.

Voyons comment l'utiliser !

import db from './dbconnector.js';

// it's already initialized... just use it!
await db.query('GET * FROM test');
// and it just works :D 
Copier après la connexion

Bonus : j'ai créé une bibliothèque !

J'utilise ce modèle si souvent qu'à la fin, j'ai décidé de créer une bibliothèque vraiment rapide et sale et de la publier sur NPM. Cela s'appelle des reports et c'est assez simple à utiliser (c'était aussi assez simple à écrire, une fois que j'ai connu le modèle).

Refaisons l'exemple ci-dessus en utilisant plutôt des reports.

import sqlite3 from 'sqlite3';
import { open } from 'sqlite';
Copier après la connexion
Copier après la connexion

La chaîne 'db' est essentiellement n'importe quel nom de chaîne que vous souhaitez donner au différé, et vous pouvez en créer autant que vous le souhaitez. Évidemment, vous n'avez pas besoin de cette bibliothèque, mais personnellement, je la trouve plutôt sympa, vous savez ?

J'espère que vous avez appris un modèle vraiment utile ici, et je suis heureux d'avoir fait partie de votre parcours d'apprentissage aujourd'hui <3

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal