首页 >web前端 >js教程 >如何在 Javascript 中创建异步构造函数?

如何在 Javascript 中创建异步构造函数?

Susan Sarandon
Susan Sarandon原创
2024-11-24 03:38:10306浏览

How to make an async constructor in Javascript?

您来到这里是因为您有一个问题:我如何等待类构造函数?如何使构造函数异步???

很抱歉,答案是你确实不能。 Javascript 中类的构造函数必须是同步的。但是,实现中存在一些替代方案可以帮助您完成您想要的操作。让我们来探索一下吧!

您可能需要这个,因为您需要在构造函数中初始化某些内容,并使其在对类进行的任何调用中可用。一个很好的例子是连接到数据库并在接受任何查询之前等待该连接建立。

这个模式非常简单!让我们从一个示例数据库连接器开始,使用 npm 上的 sqlite 模块:

import sqlite3 from 'sqlite3';
import { open } from 'sqlite';

要打开此数据库,您需要等待 open 函数。我让我友好的 AI 代码助手想出了一个“DBConnector”类,它实际上得到了正确的通用模式 - 你随处可见的模式:

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();

您只需导入它然后等待它的调用即可调用它:

import db from './dbconnector.js';

await db.connect();
await db.query('GET * FROM test');

所以现在,这里的问题当然是,你不仅需要手动调用 myDB.connect() 来启动连接,你也不能保证查询调用能够工作,比如说,如果当您的主文件正在连接时,另一个文件会执行查询。

当然,主文件可以await db.connect(); ,但是导入此模块的任何其他内容都没有任何方法可以做到这一点。您可能会想,“好吧,但我也可以在其他文件中调用 wait db.connect();,对吗?”你可以...但是每次都会重新连接到数据库,这可能会很慢,具体取决于你使用的是什么。

延迟模式

我想出的模式稍微复杂一点,但它仍然很简单,并确保每一小段代码 - 以及你自己 - 都满意。事实上,这是我自己想出来的,即使它实际上为其他人所知。它们被称为“延期”承诺。

这是它的工作原理。

// 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();

这不是一个迷人的小图案吗?当然,这是一个比基本示例更多的代码,但就我个人而言,我认为它肯定提高了主要基于异步方法的类的样板代码的标准。

让我们看看如何使用它!

import db from './dbconnector.js';

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

奖励:我建了一个图书馆!

我经常使用这种模式,最终我决定制作一个非常快速且肮脏的库并将其发布到 NPM 上。它被称为延迟,使用起来非常简单(一旦我知道了模式,编写起来也非常简单)。

让我们使用延迟来重新制作上面的示例。

import sqlite3 from 'sqlite3';
import { open } from 'sqlite';

“db”字符串基本上是您想要赋予延迟的任何字符串名称,您可以创建任意多个。显然你不需要需要这个库,但我个人认为它非常好,你知道吗?

我希望您在这里学到了真正有用的模式,我很高兴能成为您今天学习之旅的一部分

以上是如何在 Javascript 中创建异步构造函数?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn